无法删除指针的向量

时间:2013-09-02 13:47:44

标签: c++ pointers vector delete-operator

我有一个管理器类,它包含一个指向虚拟基类的指针向量,允许在那里存储各种子类。在这个管理器类的析构函数中,我希望它循环遍历它所拥有的所有指针并删除它们。但是,我尝试了一些我遇到的方法,程序在执行过程中不断崩溃。

我现有的代码如下所示: -

for (std::vector<GameState*>::iterator it = gamestates_.begin(); it != gamestates_.end(); ++it){
    delete *it;
    it = gamestates_.erase(it);
}

我还没有尝试过的一件事是使用unique_ptr,但我确信这应该可以在不使用它们的情况下处理它。如果我错了,请纠正我。

编辑:我知道我应该在循环之后清除向量,但这是我在尝试删除指针的每个常规方法之后所得到的。它似乎不喜欢删除命令。

6 个答案:

答案 0 :(得分:5)

从向量中删除元素会使迭代器无效,因此您无法继续迭代。在这种情况下,我不会擦除循环中的元素;之后我会清除矢量:

for (auto it = gamestates_.begin(); it != gamestates_.end(); ++it){
    delete *it;
}
gamestates_.clear();

虽然,如果这是在析构函数中并且矢量即将被销毁,那么也没有必要清除它。

如果你确实需要在循环内擦除(可能因为你只想删除一些元素),那么你需要更加小心以保持迭代器有效:

for (auto it = gamestates_.begin(); it != gamestates_.end();){ // No ++ here
    if (should_erase(it)) {
        it = gamestates_.erase(it);
    } else {
        ++it;
    }
}
  

我还没有尝试过的一件事是使用unique_ptr,但我确信这应该可以在不使用它们的情况下处理它。如果我错了,请纠正我。

如果您确实想通过此方式通过Steam管理动态对象,请确保遵循Rule of Three:您需要实现(或删除)复制构造函数和复制赋值运算符以防止“浅” “复制让你留下两个试图删除相同对象的向量。您还需要注意删除删除或替换它们的任何其他位置的对象。存储智能指针(或者对象本身,如果你不需要指向多态的指针)将为你处理所有这些事情,所以我总是建议你这样做。

  

我知道我应该在循环之后清除向量,但这是我在尝试删除指针的每个常规方法之后所得到的。它似乎不喜欢删除命令。

最可能的原因是您没有遵循三条规则,并且在复制矢量后意外尝试删除两次相同的对象。 GameState也可能是基类,你忘了给它一个虚拟析构函数,或者指针已经被其他代码破坏了。

答案 1 :(得分:2)

你的迭代器在每个循环中更新两次:

it = gamestates_.erase(it);

it++

你只需要第一个 - 它已经指向&#34;下一个对象&#34;在容器中。

答案 2 :(得分:0)

从向量中删除元素会使迭代器无效。按元素删除对象指针,然后clear()向量的内容。

答案 3 :(得分:0)

摆脱++it循环标题中的for

erase已经为你挺身而出。

或者,迭代,删除,然后迭代.clear()

答案 4 :(得分:0)

更喜欢使用unique_ptr。你说你应该能够在不使用它们的情况下处理它,好像获得一个智能指针为你做的工作是某种可怕的强加。

他们在那里让你的生活更轻松,你不必因为不用手工做而感到内疚。

使用现有代码,只需不要致电erase。无论如何,矢量将被摧毁,对吧?它会照顾好自己。

答案 5 :(得分:0)

问题是您要两次递增it。首先,当您调用返回下一个元素的it = .erase(it),然后调用循环++i。你可能无意中跳过了最后,事情可能会出错,更不用说你只会删除你向量的每一个元素。

一个简单的解决方法就是不要在循环中更改it(无++it)。

更好的方法是从向量的末尾实际删除数组,因为向量内部的擦除元素引入了所有后续元素的昂贵移动。您当前的算法将在N^2时间内运行。 尝试这样的事情:

while (!gamestates_.empty()) {
    delete gamestates_.back();
    gamestates_.erase(gamestates_.end()-1);
}

您也可以迭代矢量的所有元素并在之后清除它:

for (std::vector<GameState*>::iterator it = gamestates_.begin(); it != gamestates_.end(); ++it){
    delete *it;
}
gamestates_.clear();

另请注意,向量的clear()操作也在其析构函数中完成。如果删除过程是某些销毁过程的一部分,gamestates_被彻底销毁 - 您根本不必致电clear()