C++在迭代时删除列表成员:标准解决方案不起作用?

Sim*_*ini 8 c++

这是我的问题.我已经阅读了许多关于如何在迭代它时删除列表成员的问题以及我尝试了答案提出的各种解决方案.碰巧他们似乎没有工作.我有这种类的列表:

class Walker {
    public:
        Walker(int); 
        ~Walker(); 

        double *x; 
        double *y; 
        double *z; 
        double weight; 
        int molteplicity; 
};
Run Code Online (Sandbox Code Playgroud)

构造函数和析构函数如下

Walker::Walker(int particle_num) {
    x = new double[particle_num];
    y = new double[particle_num];
    z = new double[particle_num];
}

Walker::~Walker() {
    delete x;
    delete y;
    delete z;
}
Run Code Online (Sandbox Code Playgroud)

现在,列表

list<Walker> population;
Run Code Online (Sandbox Code Playgroud)

被定义为另一个类的成员.现在,如果元素molteplicity为null(通过另一个函数计算),我必须从类中删除成员,这就是我的方法:

for( it = population.begin(); it != population.end(); ) {
        if( it->molteplicity == 0 ) {
            it = population.erase(it);
        } else {
            ++it;
    }
Run Code Online (Sandbox Code Playgroud)

在运行时收到以下错误:

prog(22332)malloc:*对象0x7f838ac03a60的错误:未释放指针被释放*在malloc_error_break中设置断点以调试Abort陷阱:6

你看到错误吗?非常感谢您的帮助!!如果您需要更多代码,请告诉我.

Sho*_*hoe 8

问题与使用无关std::list,但它在析构函数中:

Walker::~Walker() {
    delete x;
    delete y;
    delete z;
}
Run Code Online (Sandbox Code Playgroud)

你已分配使用new[],而不是new,因此你必须使用delete[]delete:

Walker::~Walker() {
    delete[] x;
    delete[] y;
    delete[] z;
}
Run Code Online (Sandbox Code Playgroud)

Live demo

另请注意,molteplicity并且weight从未初始化,因此可以包含任何数字(可能与之不同0).

在这些更改后,您的程序编译并运行完美.


另外请注意,new并且delete在C++社区中,出于很好的理由通常不赞成.使用智能指针或容器,请一般遵循零规则.

最后,您可以使用更清晰的解决方案std::list::remove_if.如果您遵循这些提示,您将获得以下内容:

struct Walker {
    Walker(int num) 
        : x(num), y(num), z(num)
        , weight(0)
        , molteplicity(0)
        {}

    std::vector<double> x, y, z; 
    double weight; 
    int molteplicity; 
};
Run Code Online (Sandbox Code Playgroud)

用作:

std::list<Walker> population {...};
population.remove_if([](Walker const& w) { return w.molteplicity == 0; });
Run Code Online (Sandbox Code Playgroud)

Live demo

哪个更具可读性和更正确性.


Ada*_*amF 3

您应该实现复制构造函数,因为列表在内部使用它。当您执行如下代码时必须完成复制:list.push_back(Walker(5));。必须将临时对象移动或复制到列表中。默认复制构造函数仅复制指针,因此析构函数会两次释放相同的内存。

在这种情况下移动语义就足够了:请将此构造函数添加到您的代码中:

Walker(Walker&& other)
{
    x = other.x;
    y = other.y;
    z = other.z;
    weight = other.weight;
    molteplicity = other.molteplicity;
    //remove data from the original object to avoid freeing memory twice
    other.x = nullptr;
    other.y = nullptr;
    other.z = nullptr;
}
Run Code Online (Sandbox Code Playgroud)

并删除复制构造函数(或正确实现它):

Walker(const Walker& other) = delete;
Run Code Online (Sandbox Code Playgroud)

如果您使用指针并分配内存,那么您应该知道三法则:

三法则(也称为三巨头法则或三巨头法则)是 C++(C++11 之前)中的一条经验法则,它声称如果一个类定义了以下其中一项,那么它可能应该显式定义三个全部:

析构函数

复制构造函数

复制赋值运算符