C++ 删除指针向量时遇到问题

C++ 删除指针向量时遇到问题,c++,pointers,vector,delete-operator,C++,Pointers,Vector,Delete Operator,我有一个管理器类,它持有指向虚拟基类的指针向量,以允许在其中存储各种子类。在这个管理器类的析构函数中,我希望它遍历它所持有的所有指针并删除它们。然而,我尝试了我遇到的许多方法,程序在执行过程中不断崩溃 我的当前代码如下所示:- for (std::vector<GameState*>::iterator it = gamestates_.begin(); it != gamestates_.end(); ++it){ delete *it; it = gamestat

我有一个管理器类,它持有指向虚拟基类的指针向量,以允许在其中存储各种子类。在这个管理器类的析构函数中,我希望它遍历它所持有的所有指针并删除它们。然而,我尝试了我遇到的许多方法,程序在执行过程中不断崩溃

我的当前代码如下所示:-

for (std::vector<GameState*>::iterator it = gamestates_.begin(); it != gamestates_.end(); ++it){
    delete *it;
    it = gamestates_.erase(it);
}
for(std::vector::iterator it=gamestates_uu.begin();it!=gamestates_uu.end();++it){
删除*它;
它=游戏状态\擦除(it);
}
有一件事我还没有尝试过,那就是使用unique_ptr,但我确信它应该能够在不使用它们的情况下处理它。如果我错了,请纠正我


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

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

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

for (auto it = gamestates_.begin(); it != gamestates_.end(); ++it){
    delete *it;
}
gamestates_.clear();
for (std::vector<GameState*>::iterator 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\u ptr
,但我确信这应该能够在不使用它们的情况下处理它。如果我错了,请纠正我

如果您确实希望通过这种方式通过steam管理动态对象,那么请确保遵循:您需要实现(或删除)复制构造函数和复制赋值运算符,以防止“浅层”复制,从而留下两个试图删除相同对象的向量。您还需要注意在删除或替换对象的任何其他位置删除对象。存储智能指针(或者对象本身,如果您不需要多态性指针的话)将为您解决所有这些问题,所以我始终建议这样做

我知道我应该在循环后清除向量,但这是我在尝试了删除指针的所有常规方法后得出的结论。它似乎不喜欢delete命令


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

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

it = gamestates_.erase(it);


您只需要第一个对象-它已经指向容器中的“下一个对象”。

去掉
++it
for循环标题中的

erase
已经为您提供了帮助


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

更喜欢使用
unique\u ptr
。你说你应该能够在不使用它们的情况下处理它,就好像得到一个智能指针来为你工作是一种可怕的强加

他们的存在是为了让你的生活更轻松,你不必为没有用手做这些艰苦的工作而感到内疚


使用现有代码时,不要调用
erase
。不管怎样,向量都会被摧毁,对吗?它会自己处理所有这些问题。

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

一个简单的修复方法就是不要在循环中更改
(no
++it

更好的方法是从向量的末尾实际删除数组,因为从向量内部删除元素会导致所有后续元素的昂贵移动。您当前的算法将在
N^2
时间内工作。 试着这样做:

while (!gamestates_.empty()) {
    delete gamestates_.back();
    gamestates_.erase(gamestates_.end()-1);
}
您也可以迭代向量的所有元素,然后将其清除:

for (auto it = gamestates_.begin(); it != gamestates_.end(); ++it){
    delete *it;
}
gamestates_.clear();
for (std::vector<GameState*>::iterator it = gamestates_.begin(); it != gamestates_.end(); ++it){
    delete *it;
}
gamestates_.clear();
for(std::vector::iterator it=gamestates_uu.begin();it!=gamestates_uu.end();++it){
删除*它;
}
游戏状态清除();

还要注意,向量的
clear()
操作也在其析构函数中完成。如果删除过程是某个销毁过程的一部分,
gamestates\uuu
被彻底销毁-你根本不必调用
clear()

+1似乎有点不公平,因为你没有投票权,因为你的投票是第一个指出这一点的答案。“使用现有代码,不要调用擦除。不管怎样,向量都会被摧毁,对吗?这一切都会自己解决的。“除非不是,否则就不会!问:这是在manager类的析构函数中,我假设向量是成员子对象。这似乎也不起作用。我以前确实尝试过类似的方法,但似乎没有任何效果。就好像它不喜欢delete命令一样。愚蠢的问题:我假设我不需要包含特定的头来删除指针。@RustyC:delete
命令可以,如果它是有效的指针。是否意外复制了矢量并删除了两次对象?
GameState
是一个基类,实际对象的类型不同吗?如果是这样,请确保它有一个虚拟析构函数。如果没有,为什么要首先存储指针?Gamestate拥有对init、render、update和close的虚拟调用,但它的每个子级还拥有许多自己的函数和变量