很抱歉,如果已经提出此问题,但我很难搜索析构函数和访问冲突=)
这是场景的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的析构函数被声明为虚拟时,为什么存在访问冲突?
答案 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
。