4

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

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

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

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

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

4

6 回答 6

6

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

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,但我确信这应该能够在不使用它们的情况下处理它。如果我错了,请纠正我。

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

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

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

于 2013-09-02T13:49:58.847 回答
2

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

it = gamestates_.erase(it);

it++

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

于 2013-09-02T13:50:19.547 回答
0

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

它们的存在是为了让您的生活更轻松,您不必为没有手工完成艰苦的工作而感到内疚。

使用您现有的代码,不要调用erase. 无论如何,向量都会被破坏,对吧?它会自己处理这一切。

于 2013-09-02T13:54:19.333 回答
0

问题是您要增加it两次。首先,当您调用it = .erase(it)which 返回下一个元素时,然后在循环中++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()

于 2013-09-02T13:54:23.987 回答
0

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

于 2013-09-02T13:49:42.653 回答
0

摆脱++it你的for循环头。

erase已经为你进步了。

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

于 2013-09-02T13:51:17.833 回答