CRT virtual destructor

2019-06-20 17:18发布

I ran into a heap corruption today caused by different CRT settings (MTd MDd) in my dll and my actual project. What I found strange is that the application only crashed when I set the destructor in the dll to be virtual. Is there an easy explanation for that? I get that I can't free memory that's not on my heap, but where exactly is the difference when I define the destructor as non-virtual.

Some Code just to make it a little clearer

The DLL

#pragma once
class CTestClass
{
public:
    _declspec(dllexport) CTestClass() {};
    _declspec(dllexport) virtual ~CTestClass() {};
};

And my project

int main(int argc, char* argv[])
{
    CTestClass *foo = new CTestClass;
    delete foo; // Crashes if the destructor is virtual but works if it's not
}

3条回答
仙女界的扛把子
2楼-- · 2019-06-20 17:57

You didn't really post enough code to be sure. But your example should NOT crash because there isn't anything wrong with it:

int main(int argc, char* argv[])
{
    // 1. Allocated an instance of this class in *this/exe* heap, not the DLL's heap
    // if the constructor allocates memory it will be allocated from the DLL's heap
    CTestClass *foo = new CTestClass;

    // 2. Call the destructor, if it calls delete on anything it will be freed from the DLL's heap since thats where the destructor is executing from. Finally we free the foo object from *this/exe* heap - no problems at all.
    delete foo;
}

I suspect that in your real code you must be using operator delete on an object who's operator new was executed in the context of the dll. And without the virtual keyword you likely miss the destructor call which is doing the cross context delete.

查看更多
beautiful°
3楼-- · 2019-06-20 18:03

virtual destructor is only necessary when you have some inheritance hierarchy tree. Virtual keyword will make sure that pointer to the actual object (not the type of the object) is destroyed by finding its destructor in the Vtable. Since in this example, going by the code you gave, CTestClass is not inheriting from any other class, it is in a way a base class and hence doesn't need a virtual destructor. I'm assuming there maybe another under the hood implementation rule causing this but you shouldn't use virtual with base classes. Anytime you create a derived object, you also create its base (for polymorphic reason) and the base always gets destroyed (the derived only gets destroyed if you make the destructor for it virtual, hence placing it in a runtime vlookup (virtual) table).

Thanks

查看更多
祖国的老花朵
4楼-- · 2019-06-20 18:20

There is a difference between

class CTestClass
{
public:
    _declspec(dllexport) CTestClass() {}
    _declspec(dllexport) virtual ~CTestClass() {}
};

and

__declspec(dllexport) class CTestClass
{
public:
     CTestClass() {}
     virtual ~CTestClass() {}
};

In the former case you instructed a compiler to export only two member functions: CTestClass::CTestClass() and CTestClass::~CTestClass(). But in the latter case you would instruct a compiler to export the table of virtual functions as well. This table is required once you have got a virtual destructor. So it might be the cause of the crash. When your program tries to call virtual destructor, it looks for it in the associated virtual functions table, but it is not initialized properly so we do not know where it really points then. If your destructor is not virtual, then you do not need any virtual function table and everything works just fine.

查看更多
登录 后发表回答