【问题标题】:vector::erase causing strange behaviorvector::erase 导致奇怪的行为
【发布时间】:2013-07-15 09:14:02
【问题描述】:

我正在尝试创建一个垂直滚动的射击游戏,当你按下空格键时会创建一个子弹,然后当子弹离开屏幕时,子弹会被摧毁。我通过标记为vector<BULLET> bullets; 的向量跟踪子弹当我尝试销毁屏幕外的任何子弹时,我会遇到大量错误,例如: c:\mingw\bin\..\lib\gcc\mingw32\4.7.0\include\c++\bits\stl_algobase.h|384| required from '_OI std::__copy_move_a(_II, _II, _OI) [with bool _IsMove = true; _II = BULLET*; _OI = BULLET*]'|

我的代码如下所示:

for( auto it = bullets.begin(); it != bullets.end(); ){
    if( it->is_dead()){
        it = bullets.erase(it);
    }else{
        it++;
    }
}

让我感到沮丧的部分是我有类似的循环,它删除任何需要在包含指针的向量中删除的游戏对象:

for( auto it = activeInstances.begin(); 
it != activeInstances.end(); ){
    if( (*it)->is_dead()){
        it = activeInstances.erase(it);
    }else{
        it++;
    }
}

这个工作得很好。

编辑:我不确定它是否有区别,但仅供参考,我将稍后出现在向矢量添加项目符号的同一函数中添加部分:

if( key[SPACE] && reload == 0){
    reload = reloadTime;
    BULLET newBullet;
    newBullet.init( x, y);
    bullets.push_back( newBullet);
}

【问题讨论】:

  • BULLET 有移动构造函数吗?
  • 也许你应该替换 if( it->is_dead()){ 与来自波纹管循环的完全相同的代码 if( (*it)->is_dead()){ ... 你必须访问对象在迭代器中,您可以使用 *it
  • it-> 对访问迭代器的对象是有效的,但如果向量中的对象本身是点类型,则您必须通过 (*it)-> 进行实际上取消引用两次:迭代器和迭代器持有的任何类型。 BULLET 是指针类型吗?
  • 你有非公开的复制或移动构造函数吗?
  • 我确实尝试将 it->is_dead() 更改为 (*it)->is_dead() 只是为了确保这不是问题并且会引发错误,因为项目符号是 BULLET 的向量,而 activeInstances 是 *OBJECT

标签: c++ vector erase allegro


【解决方案1】:

您的代码片段不同:

if( it->is_dead()){

对比

if( (*it)->is_dead()){

【讨论】:

  • 这些sn-ps使用的向量也是如此。这本身不是问题。
  • 你是对的,BULLET 的定义很重要,但是代码差异提示了错误的可能原因。
  • 如果您能详细说明最后一个声明 collapsar,我将不胜感激。一个是引用对象向量,另一个是引用指向对象的指针向量,因此代码中的唯一区别不应该导致任何问题,对吧?
  • @JustinMcFall:您没有提供 BULLET 的定义,但强调了与 activeInstances 的代码段的类比。很高兴您能按照 Doctorlove 的提示解决您的问题。
【解决方案2】:

我建议使用 erase-remove idiomstd::vector 中删除项目 (可以考虑this StackOverflow Q&A详细讨论,也适用于其他容器):

// Erase elements matching "erasing_condition" from vector "v"
v.erase( std::remove_if(v.begin(), v.end(), erasing_condition), v.end() );

在您的特定情况下,您可能希望使用如下代码:

//
// Erase elements matching "BULLET.is_dead()" from vector "bullets".
// ("bullets" is a "vector<BULLET>")
//
bullets.erase
(     
    std::remove_if
    ( 
        bullets.begin(), 
        bullets.end(), 

        // Erasing condition
        [](const BULLET& bullet)
        { 
            return bullet.is_dead(); 
        }   
    ), 
    bullets.end() 
);

顺便说一句:作为风格指南,我更喜欢 Bullet 而不是 BULLET 作为 C++ 类名(ALL_UPPERCASE_STYLE 通常保留用于 C++ 中的预处理器宏...) .

【讨论】:

  • 我非常欣赏风格指南,我同意这样会更好。我也尝试了您的建议,但仍然抛出错误。第一个是新的,是: stl_algo.h 1158 error: no match for 'operator=' in '__result.__gnu_cxx::__normal_iterator&lt;_Iterator, _Container&gt;::operator*&lt;BULLET*, std::vector&lt;BULLET&gt; &gt;() = std::move&lt;BULLET&amp;&gt;((* &amp; __first.__gnu_cxx::__normal_iterator&lt;_Iterator, _Container&gt;::operator*&lt;BULLET*, std::vector&lt;BULLET&gt; &gt;()))' candidate is: BULLET&amp; BULLET::operator=(BULLET&amp;) 之后,我得到了与在最后一行 bullets.erase 标记的 OP 中相同的错误
【解决方案3】:

正如有人在其中一个 cmets 中提到的那样,问题是我没有在我的 BULLET 类中使用移动构造函数(我是一个完全的菜鸟,在被提及之前我什至不知道那是什么) .不过真的很感谢大家的帮助,我真的学到了很多!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-27
    • 2011-03-06
    • 1970-01-01
    相关资源
    最近更新 更多