Placement new crashing when used with virtual inheritance hierarchy in Visual C++

跟風遠走 提交于 2019-12-24 07:04:07

问题


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?


回答1:


malloc returns some fresh memory address, operator new places a Bat at that address, and conversion to Animal* adjusts the address. Now the bat variable points somewhere inside the malloc block. freeing it is impossible.

Bat* bat0 = new(malloc(sizeof(Bat))) Bat;
Animal* bat = bat0;
std::cout << bat0 << " " << bat << "\n";

gcc prints two identical addresses, while VC++ 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*:

  free(dynamic_cast<void*>(bat));

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, but free 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 and operator delete

void* ::operator new(size_t sz) { return my_managed_malloc(sz); }
void ::operator delete (void* ptr) { return my_managed_free(ptr); }

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 .



来源:https://stackoverflow.com/questions/41246633/placement-new-crashing-when-used-with-virtual-inheritance-hierarchy-in-visual-c

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!