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

C++ deleting a list member while iterating: standard solution is not working?

本文关键字:标准 解决方案 不起作用 成员 列表 迭代 删除 删除列 C++      更新时间:2023-10-16

这是我的问题。我已经阅读了许多关于如何在迭代列表时删除列表成员的先前问题,并尝试了答案提出的各种解决方案。碰巧它们似乎不起作用。我有一个此类类的列表:

class Walker {
    public:
        Walker(int); 
        ~Walker(); 
        double *x; 
        double *y; 
        double *z; 
        double weight; 
        int molteplicity; 
};

构造函数和析构函数如下

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;
}

现在,列表

list<Walker> population;

定义为另一个类的成员。现在,如果元素的摩尔率为空(通过另一个函数计算),我必须动态地从类中删除成员,这就是我的做法:

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

在运行时收到以下错误:

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

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

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

Walker::~Walker() {
    delete x;
    delete y;
    delete z;
}

您是使用 new[] 而不是 new 进行分配的,因此您必须使用 delete[] 而不是 delete

Walker::~Walker() {
    delete[] x;
    delete[] y;
    delete[] z;
}

现场演示

另请注意,molteplicityweight 永远不会初始化,因此可以包含任何数字(可能与 0 不同)。

完成这些更改后,您的程序可以完美编译并运行。


另请注意,newdelete在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; 
};

并用作:

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

现场演示

这既更具可读性,也更正确。

你应该实现复制构造函数,因为列表在内部使用它。复制必须在执行如下代码时完成: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;
}

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

Walker(const Walker& other) = delete;

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

三法则

(也称为三巨头法则或大三法则) 三)是C++(C++11之前)的经验法则,声称如果 一个类定义它应该显式定义的以下内容之一 定义所有三个:

破坏者

复制构造函数

复制赋值运算符