【问题标题】:Weird behaviour encapsulated std::list in std::vector sometimes奇怪的行为有时将 std::list 封装在 std::vector 中
【发布时间】:2021-08-29 19:06:00
【问题描述】:

我正在开发一款 RTS 游戏。这个游戏有建筑物和演员。建筑物或演员是建筑物或演员类的实例。这些实例存储在 std::vector 中,以便通过迭代器 id 轻松交互。

演员和建筑物可以执行任务,它们存储在类实例化的 std::list 中,换句话说,列表存在于 std::vector<actors> 中。现在的问题是,当有关此任务的信息需要检索或必须从列表中删除任务时,程序经常会因“访问冲突”、“尝试在空列表上弹出_front”或“尝试调用 front”而崩溃() 在一个空列表上”。尽管前一行代码是仔细检查列表是否确实不为空!它也很难重现,因为它经常发生。

我怀疑不知何故迭代器或指针会失效,因为列表存在于向量中。我试图通过为 1600 个单位和 1600 座建筑物保留空间来规避这一点。但是问题仍然存在。

   if (!this->listOfOrders.empty()) {
       switch (this->listOfOrders.front().orderType) { //error here calling front() on empty list
       case stackOrderTypes::stackActionMove:
           this->updateGoal(this->listOfOrders.front().goal, 0);
           break;
       case stackOrderTypes::stackActionGather:
           this->updateGoal(this->listOfOrders.front().goal, 0);
           this->setGatheringRecource(true);
           break;
       }
}

我真的很茫然。

简化的类结构来说明:

enum class stackOrderTypes
{
    stackActionMove,
    stackActionGather
    //and so on...
};


struct goal
{
 int x;
 int y;
}

struct orderStack
{
    cords goal;
    stackOrderTypes orderType;
};

class actors
{
public:
   //other functions here
    void doNextStackedCommand();
    void stackOrder(cords Goal, stackOrderTypes orderType);

private:
    //other stuff goes here
    std::list<orderStack> listOfOrders;
};

std::vector<actors> listOfActors; //all actors live in here

【问题讨论】:

  • 什么是“迭代器 id”?我只知道迭代器,它可以通过对关联容器的特定操作而失效。
  • 您的症状表明行为不明确。主要嫌疑人将使用无效对象或未经检查的并发性。
  • 可能是数据竞争。两个或多个线程可能同时修改您的数据。

标签: c++ exception stdvector invalidation stdlist


【解决方案1】:

要知道是什么问题导致了这个错误,您首先需要在代码中准确找到问题所在的位置。 但是,根据您的描述,我看到了您的问题的可能原因:items removals

我想您有一些循环遍历您的订单,并且在某些情况下您会从订单列表中删除订单。检查您的代码是否如下所示:

for (auto it = orderList.begin(); it != orderList.end(); ++it)
{
  // Some code there
  if (OrderIsFinished() == true)
    orderList.erase(it);
  // Some code there
}

这是一个常见的错误。调用erase后,迭代器指向的项目被删除并失效。为了在删除后保持迭代器的一致性,您需要更改遍历所有元素的方式:

auto it = orderList.begin();
while (it != orderList.end())
{
    // Some code there
    if (OrderIsFinished() == true)
      it = orderList.erase(it);
    else
      ++it;
}

【讨论】:

    【解决方案2】:

    这实际上是一个数据竞争问题。有一个 std::async 更新程序正在为构建运行,而更新函数在主线程中被调用!

    【讨论】:

      猜你喜欢
      • 2011-03-06
      • 2016-03-02
      • 2022-01-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-06-15
      • 1970-01-01
      相关资源
      最近更新 更多