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的虚拟调用,但它的每个子级还拥有许多自己的函数和变量