CRT virtual destructor

…衆ロ難τιáo~ 提交于 2019-12-08 19:40:02

问题


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
}

回答1:


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.




回答2:


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.




回答3:


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



来源:https://stackoverflow.com/questions/17531558/crt-virtual-destructor

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