基类虚拟析构函数访问冲突

时间:2009-12-03 03:33:54

标签: c++ dll access-violation virtual-destructor

很抱歉,如果已经提出此问题,但我很难搜索析构函数和访问冲突=)

这是场景的C ++伪代码:


在DLL1中(用/ MT编译)

class A
{
public:
    virtual ~A()      <== if "virtual" is removed, everthing works OK
    {
    }
}

class B : public A
{
public:
    __declspec( dllexport ) ~B()  // i did try without exporting the destructor as well
     {
     }      <== Access Violation as it returns (if fails in assembly at delete operator...)
}

在DLL2中链接到DLL1

main()enter code here
{
    B* b = new B();
    delete b;           <== Access Violation
}

发生了什么事?我有脑残吗?如果我使A的析构函数非虚拟,一切正常 - 即使A和B的析构函数被调用(好像A的析构函数是虚拟的 - 这是因为它是公开的吗?)。

我的主要问题是 - 当base classe的析构函数被声明为虚拟时,为什么存在访问冲突?

2 个答案:

答案 0 :(得分:1)

谢谢你们!谢谢ChrisW ..看起来就是正在发生的事情。 我需要添加的其他东西是静态分配器(static createNew()):

class A
{
public:
  __declspec( dllexport ) static void destroy(A* self) { delete self; }
protected:
  virtual ~A() {}
};

class B : public A
{
 protected: 
   B();
 public:
   __declspec( dllexport ) static B* createNew() { return new B(); }
}

int main()
{
  B* b = B::createNew()
  A::destroy(b); //instead of delete b
  return 0;
}

(在我的部署环境下,使用/ MD进行编译不是我的选择)

答案 1 :(得分:0)

因为它在delete运算符中崩溃,并且因为你说你正在使用/MT进行编译,我相信原因是你的两个DLL不共享同一堆:因为它们都是链接对于静态库,他们每个人都获得自己的运行时堆的私有副本;并且你有效地从一个堆中分配一个DLL中的内存,并从另一个堆中删除另一个DLL中的内存。

要解决此问题,您可以声明析构函数受到保护,并且不导出它。相反,创建一个静态销毁函数:

class A
{
public:
  __declspec( dllexport ) static void destroy(A* self) { delete self; }
protected:
  virtual ~A() {}
};

int main()
{
  B* b = new B();
  A::destroy(b); //instead of delete b
  return 0;
}

或者,您可能更喜欢这个,因为它不涉及更改源代码,确保构建两个DLL以使用相同的堆,即使用C版本的C运行时,我认为这意味着使用/MD选项代替/MT