I am using virtual inheritance with a selection of classes in c++. It is currently crashing on destruction. It seems to compile fine in the online compilers, however when I run in Visual Studio, it crashes.
I have a pure virtual base class, which is being inherited virtually by its implementation. I then have a third class that is inheriting from the implementation regularly. I am using an internal system for creating and releasing memory. Under the hood it is using a placement new with a aligned malloc. It is then using free to free the memory. I have created this minimum example. It is not exactly what I am doing but I seem to get a similar problem.
#include <iostream>
#include <string>
int main()
{
class Animal {
public:
Animal() { }
virtual ~Animal() { }
virtual void eat() { }
};
class Mammal : public virtual Animal {
public:
virtual void breathe() { }
};
class WingedAnimal : public virtual Animal {
public:
virtual void flap() { }
};
// A bat is a winged mammal
class Bat : public Mammal, public WingedAnimal {
};
Animal* bat = new(malloc(sizeof(Bat))) Bat;
bat->~Animal();
free(bat);
printf("Done!");
}
Like I said, this example will print "Done" in the online compiler. However in Visual Studio 2015 it seems to crash on free of the bat object. I am fairly new to virtual inheritance and placement new. Does anyone see the problem?
malloc
returns some fresh memory address,operator new
places aBat
at that address, and conversion toAnimal*
adjusts the address. Now thebat
variable points somewhere inside themalloc
block.free
ing it is impossible.gcc
prints two identical addresses, whileVC++
prints two different ones. Either behaviour is perfectly normal and allowed by the standard, even when no multiple inheritance is involved. Most compilers don't actually adjust the address with single inheritance, but there are some exceptions.To be on the safe side, don't rely on the two addresses being the same.
It is possible to recover the original address by dynamic casting to
void*
:should be OK. Of course a virtual function is required for the dynamic cast to work, as usual.
Update:
dynamic_cast<void*>
recovers the initial pointer, butfree
still crashes with VC++. I have no idea why.The right method to integrate a third party memory manager in your C++ program is to overload
operator new
andoperator delete
Place these in any one C++ file in your program (if you have DLLs, then in all DLLs) and use C++ normally, without ill-defined pointer tricks.
For more info, http://en.cppreference.com/w/cpp/memory/new/operator_new .