A box2d engine is created as usual with “Physics a”. This works fine in the example. But, if we are adding a new instance as std::vector with myphysics.push_back({});
the following error is shown on the command-line after executing the binary file:
“double free or corruption (!prev) Aborted (core dumped)”
I have absolutely no idea, what the message mean or what the problem is with a vector of box2d engines. Here is the sourcecode:
// 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;
}
The problem essentially is that b2World
is not designed to be copyable.
I can reproduce a double free simply using the following code block:
{
b2World woo{b2Vec2(0.f, 9.8f)};
b2World poo{woo};
}
This problem can be recognized via source code analysis.
Taking a look at the b2World
class, we can see that it has no user defined copy constructor and no user defined copy assignment method. Furthermore the code uses no mechanism to prevent the compiler from defining these. So the compiler follows the rules for special member functions and automatically generates the copy constructor and copy assignment operator. Neither of these automatically generated methods will know how to deal with any dynamically allocated memory that b2World
causes to be allocated (like through its composition of a b2BroadPhase
instance). These automatically generated methods simply call component instances' copy methods which in this case results in any pointers to allocated memory to have those addresses copied. Then on destruction, a destructor like that for the b2BroadPhase
class calls the C-library free
function for that allocated memory for the original instance and again for every copy.
Bam!!... double free!
If you are wondering, here's some ways to avoid this problem:
b2World
copy constructor or copy assignment operator. For example, instead of using a vector of b2World
instances, make it a vector of pointers to b2World
instances. You might do that by having your Physics
class's world
member defined instead as something like: std::unique_ptr<b2World> world{std::make_unique<b2World>(b2Vec2(0.f, 9.8f))};
. If you don't mind rebuilding Box2D, you might also want to add explicitly deleted definitions of these special functions to help with avoiding these copy operations (just add the lines: b2World(const b2World& o) = delete; b2World& operator=(const b2World&) = delete;
into the class definition for b2World
in its header file).