I wonder if any C++ gurus out there could shed some light on this strange situation. One of the examples that comes with the Box2D physics engine is crashing with the message "pure virtual method called", but only with a certain compiler (and only in release build).
Box2D as you may know is a pretty solid chunk of code so I am thinking this may be a problem with the compiler, especially given that it only happens with this particular compiler. I am using mingw32 on Windows7:
> gcc.exe --version
gcc version 4.4.0 (GCC)
Below is an cut-down excerpt of the relevant parts of Box2D. You can check out the full source at:
b2Shape.h
b2CircleShape.h
b2CircleShape.cpp
SensorTest.h
//base class
class b2Shape
{
public:
virtual ~b2Shape() {}
virtual b2Shape* Clone(b2BlockAllocator* allocator) const = 0;
};
//sub class
class b2CircleShape : public b2Shape
{
public:
b2CircleShape();
b2Shape* Clone(b2BlockAllocator* allocator) const;
};
inline b2CircleShape::b2CircleShape() {}
b2Shape* b2CircleShape::Clone(b2BlockAllocator* allocator) const
{
void* mem = allocator->Allocate(sizeof(b2CircleShape));
b2CircleShape* clone = new (mem) b2CircleShape;
*clone = *this;
return clone;
}
Note the placement new in the Clone function.
Now the execution that causes the problem boils down to this:
{
b2CircleShape shape;
shape.Clone(allocator); //ok
}
{
b2CircleShape shape;
shape.Clone(allocator); //"pure virtual method called"
}
After educating myself on how a virtual method could ever be called in the first place, I tried to figure out why it was happening here, since it doesn't fit the classic case of calling a virtual function in the base class constructor. After a prolonged session of stumbling around blindly I came up with the minimal case above.
My wild guess is that the compiler is smart enough to see that these two b2CircleShape instances are not in use in the same scope, so it only allocates space for one and reuses it. After the first instance is destructed, the vtable is as expected, hosed. Then for some reason when the second instance is constructed, the vtable is not constructed again...?
I came up with two things that avoid the problem, but like I say it seems more like a compiler issue so I'm not suggesting this code needs to be changed.
Dubious fix number 1 is to comment out the virtual destructor definition in the base class. All the information I have read on this subject suggests this is not the answer. (Interestingly, I found it was not enough to simply remove the 'virtual' modifier from the base class destructor. My understanding is that compiler would provide a default destructor ~b2Shape() {} if none was specified, so why is the outcome different if I actually specify what the default would be anyway? Well, this is beside the point really...)
Not-so-dubious fix number 2 I discovered was to remove the 'inline' from the sub-class constructor. Perhaps there is something about placement new, inline construction and the reused instances in the same stack frame that does not play nicely together. (UPDATE: further checking shows the placement new to be irrelevant)
Some more research tells me that the compiler is free to do whatever it likes regarding 'inline' suggestions, so perhaps the other compilers don't have this problem because they are ignoring the 'inline'?