CRT虚拟析构函数

时间:2013-07-08 16:28:46

标签: c++ visual-studio-2010 crt virtual-destructor

我今天遇到了由我的dll和我的实际项目中的不同CRT设置(MTd MDd)引起的堆损坏。 我发现奇怪的是,当我将dll中的析构函数设置为虚拟时,应用程序才崩溃。 对此有一个简单的解释吗?我知道我无法释放那些不在我堆上的内存,但是当我将析构函数定义为非虚拟内容时,区别在哪里。

一些代码只是为了让它更清晰

DLL

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

我的项目

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 个答案:

答案 0 :(得分:2)

之间存在差异
class CTestClass
{
public:
    _declspec(dllexport) CTestClass() {}
    _declspec(dllexport) virtual ~CTestClass() {}
};

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

在前一种情况下,您指示编译器仅导出两个成员函数:CTestClass :: CTestClass()和CTestClass :: ~CTestClass()。但在后一种情况下,您将指示编译器也导出虚函数表。一旦获得虚拟析构函数,就需要此表。所以它可能是崩溃的原因。当你的程序试图调用虚拟析构函数时,它会在关联的虚函数表中查找它,但是它没有正确初始化,所以我们不知道它真正指向的位置。如果你的析构函数不是虚拟的,那么你不需要任何虚函数表,一切正常。

答案 1 :(得分:0)

你没有真正发布足够的代码来确定。但是你的例子不应该崩溃,因为它没有任何问题:

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;
}

我怀疑在您的真实代码中,您必须对在dll上下文中执行operator new的对象使用operator delete。如果没有virtual关键字,您可能会错过正在执行交叉上下文删除的析构函数调用。

答案 2 :(得分:0)

只有拥有一些继承层次结构树时才需要

虚拟析构函数。虚拟关键字将确保通过在Vtable中查找其析构函数来销毁指向实际对象(而不是对象类型)的指针。因为在这个例子中,通过你给出的代码,CTestClass不是从任何其他类继承,它在某种程度上是一个基类,因此不需要虚拟析构函数。我假设可能有另一个引擎盖实现规则导致这个但你不应该使用虚拟基类。任何时候你创建一个派生对象,你也创建它的基础(出于多态的原因)并且总是被销毁(如果你为它构造虚拟的析构函数,派生只会被销毁,因此将它放在运行时vlookup(虚拟)表中)

由于