【问题标题】:C++ deleting from a vector of objectsC++ 从对象向量中删除
【发布时间】:2013-08-28 00:10:54
【问题描述】:

我有一些包含对象的向量,并且我有一系列嵌套的循环来获取我想要的对象

if (_dir->Instance()->isDebug())
{
    Utils::LogTextWithInt("growing timers size: ", _glo->Instance()->getGrowingTimers().size());
    for (int i=0; i < _glo->Instance()->getGrowingTimers().size(); i++)
    {
         GrowingTimer _growingTimer = _glo->Instance()->getGrowingTimers().at(i);

        std::cout << "growing timer Field id and plant id: " << _growingTimer.getFieldID() << " - "
                    << _growingTimer.getPlantID() << std::endl;
    }
}

std::vector<GrowingTimer>::iterator _gtIterB = _glo->Instance()->getGrowingTimers().begin();

for (_gtIterB; _gtIterB != _glo->Instance()->getGrowingTimers().end(); ++_gtIterB)
{       
    for (std::vector<Field>::iterator _fIterB = _glo->Instance()->getFields().begin();
         _fIterB != _glo->Instance()->getFields().end(); ++_fIterB)
    {          
        if (_gtIterB->getFieldID() == _fIterB->getFieldNumber())
        {
            for (std::vector<Plant>::iterator _pIterB = _fIterB->getPlants().begin();
                 _pIterB != _fIterB->getPlants().end(); )
            {
                if (_gtIterB->getPlantID() == _pIterB->getPlantID())
                {
                    Utils::LogText("gt and plant ID's match");
                    Utils::LogTextWithInt("Plant ID after matching: ", _pIterB->getPlantID());

                    // Wiggle our plant.
                    Utils::wiggleNode(_pIterB->getPlantSprite(), 10.0f, 5.0f);

                    _pIterB->setPlantStoppedGrowing(true);

                    _gtIterB = _glo->Instance()->getGrowingTimers().erase(_gtIterB);

                    ++_pIterB;
                }
                else
                {
                   ++_pIterB;
                }

            }
        }
    }
}

输出是:

growing timers size:  2
growing timer Field id and plant id: 7620 - -2130819608
growing timer Field id and plant id: 7620 - -2130802800
gt field id:  7620 
gt plant id:  -2130819608
gt and plant ID's match
Plant ID after matching:  -2130819608
deleted
gt and plant ID's match
Plant ID after matching:  -2130802800
deleted
gt field id:  7620
gt plant id:  -2130802800
gt and plant ID's match
Plant ID after matching:  -2130802800

在这一切之后我崩溃了:

0x209eff0:  addb   %ah, %gs:115(%ecx,%ebp,2)
0x209eff5:  jo     0x209f063                 ; "nitWithCondition:"
0x209eff7:  popal  
0x209eff8:  jns    0x209f048                 ; "'v'"
0x209effa:  popal  
0x209effb:  insl   
0x209effc:  incl   %esi
0x209effe:  outsl  
0x209efff:  jb     0x209f04c                 ; "ckBeforeDate:"
0x209f001:  jns    0x209f03e                 ; "Name:"
0x209f004:  jbe    0x209f067                 ; "ithCondition:"
0x209f006:  insb   
0x209f007:  jne    0x209f06e                 ; "ition:"
0x209f009:  cmpb   (%eax), %al
0x209f00b:  popl   %edi
0x209f00c:  jo     0x209f080                 ; "lSinceNow"

基本上,现在我有一个匹配项并且我对它采取了行动,我想删除_gIterB 中的位置,因为它不再需要。如果您愿意运行正在运行的定时事件,则此向量会不断添加为“跟踪器”,以便在计时器完成时我们知道计时器用于哪个对象,并可以返回到它以执行后续步骤。

编辑:GrowingTimer 的向量存储 fieldID 和“正在生长”的 PlantID,以便我们可以返回它。

字段向量存储用户拥有的所有字段,并且作为成员,每个字段对象都有一个字段中植物的向量。 8 株植物到 1 块田地。

用户创建的每个字段都有一个唯一的 ID,下面的输出是一个字段中有 2 个植物。

【问题讨论】:

  • 因为向量使用数组作为其底层存储,擦除向量末端以外的位置的元素会导致容器将擦除段后的所有元素重新定位到它们的新位置。因此,删除元素后迭代器无效。我通常做的是将要删除的事物的索引保存到一个单独的向量中,然后在 kloop 完成后遍历并擦除这些元素。
  • 多个字段可以有相同的ID吗?因为如果不是,这可以简化
  • @MooingDuck 我在上面进行了编辑以概述这一点。
  • @JerryJeremiah - 所以你说要创建一个临时向量,其中包含要删除的迭代器并定期运行该向量,获取要删除的迭代器并执行 erase()那些迭代器的GrowingTimer?

标签: c++ c++11 vector crash


【解决方案1】:
for (auto _gtIterB=grow_timers.begin(); _gtIterB!=grow_timers.end(); ++_gtIterB) {     
    ...
    _gtIterB = _glo->Instance()->getGrowingTimers().erase(_gtIterB);
    .... 
}

所以基本上,这里有两个问题。

  • 当您擦除 _gtIterB 时,您会为其分配下一个增长计时器的位置。这意味着您已跳过将此种植计时器与许多植物进行比较。我认为这很糟糕,但可能不会导致您的崩溃。
  • 如果您在 _gtIterB 是最后一个有效的增长计时器时擦除它,它被设置为结束迭代器,那么当您进入 for 循环的下一部分时,您将再次拥有 ++_gtIterB,导致它超过结尾,导致谁知道会发生什么。这绝对是坏事。

我不确定这些是否会导致您的崩溃。

但这是我对更快且深度嵌套的代码的解释:http://ideone.com/zcfnv8

【讨论】:

  • 我正在尝试这里概述的内容:stackoverflow.com/questions/991335/…
  • @Jason:你的意思是说for (it=Entities.begin(); it!=Entities.end(); )而不是你所拥有的那部分?
  • 它们似乎也增加了迭代器,我认为这有点奇怪,因为您可以将其作为 for 循环的一部分。
  • @Jason:实际上,这正是问题所在。如果您调用了擦除,您不能将迭代器作为 for 循环的一部分进行递增。这就是你崩溃的原因。查看您链接的代码。它擦除,或它推进迭代器。不要两者都做。
  • 但是我正在从与 for 循环使用的不同向量中删除一个元素。我正在从 GrowingTimers 的主 For 循环中删除...
猜你喜欢
  • 2015-02-03
  • 1970-01-01
  • 2014-05-05
  • 2014-04-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多