Box2d引擎作为std :: vector

时间:2018-04-09 08:18:46

标签: box2d

像往常一样用“物理a”创建box2d引擎。这在例子中工作正常。但是,如果我们使用myphysics.push_back({});将新实例添加为std :: vector,则在执行二进制文件后,命令行上会显示以下错误:

  

“双重免费或腐败(!prev)Aborted(core dumped)”

我完全不知道,消息的含义是什么,或者box2d引擎的向量是什么问题。这是源代码:

// g++ -std=c++14 -lBox2D rrt.cpp
#include <Box2D/Box2D.h>
#include <vector>

class Physics {
public:
  b2World world{b2Vec2(0.f, 9.8f)};
};

class RRT {
public:
  std::vector<Physics> myphysics;
  RRT() {
    myphysics.push_back({}); 
    //Physics a;
  }
};

int main()
{ 
  RRT myrrt;
}

1 个答案:

答案 0 :(得分:1)

问题主要在于b2World不是可复制的。

我可以使用以下代码块重现双重免费:

{
    b2World woo{b2Vec2(0.f, 9.8f)};
    b2World poo{woo};
}

可以通过源代码分析识别此问题。

看一下b2World类,我们可以看到它没有用户定义的复制构造函数,也没有用户定义的复制赋值方法。此外,代码不使用任何机制来阻止编译器定义它们。因此编译器遵循special member functions的规则并自动生成复制构造函数和复制赋值运算符。这些自动生成的方法都不知道如何处理b2World导致分配的任何动态分配的内存(例如通过其b2BroadPhase实例的组合)。这些自动生成的方法只需调用组件实例&#39;复制方法,在这种情况下会导致指向已分配内存的任何指针以复制这些地址。然后在销毁时,类b2BroadPhase类的析构函数为原始实例的已分配内存调用C库free函数,并为每个副本再次调用。

Bam !! ......免费加倍!

如果您想知道,可以通过以下方法避免此问题:

  1. 不要做任何调用编译器定义的b2World复制构造函数或复制赋值运算符的事情。例如,不是使用b2World个实例的向量,而是将其作为指向b2World个实例的指针的向量。您可以将Physics班级的world成员定义为以下内容:std::unique_ptr<b2World> world{std::make_unique<b2World>(b2Vec2(0.f, 9.8f))};。如果您不介意重建Box2D,您可能还想添加这些特殊函数的显式删除定义,以帮助避免这些复制操作(只需将行b2World(const b2World& o) = delete; b2World& operator=(const b2World&) = delete;添加到{{1}的类定义中在其头文件中)。
  2. 更新Box2D代码以正确处理复制构造和复制分配。在我看来,这比选项1要难得多。
  3. 使用专为支持复制构建和复制分配而设计的备用物理引擎。无耻的插件:我偏向PlayRho作为替代品。它基本上是Box2D的衍生作品(fork)。 PlayRho也没有任何问题,但除了支持复制外,它还具有其他功能,并且具有超过99%的单元测试覆盖率。