C++ 在VC6 dll中使用auto_ptr导致崩溃
以下代码在VC9下运行正常。但是,在VC6下,我将立即遇到崩溃,并显示以下消息 调试断言失败 节目: C:\Projects\use\u dynamic\u link\Debug\use\u dynamic\u link.exe 文件:dbgheap.c行:1044 表达方式: _crtisValidHeapPointerUserData 是否不允许在VC6下导出自动ptr 通过DLL导出STL集合类是一个已知的问题 但是,我在谷歌上搜索了一下,没有看到任何关于std::auto_ptr的内容C++ 在VC6 dll中使用auto_ptr导致崩溃,c++,visual-c++,C++,Visual C++,以下代码在VC9下运行正常。但是,在VC6下,我将立即遇到崩溃,并显示以下消息 调试断言失败 节目: C:\Projects\use\u dynamic\u link\Debug\use\u dynamic\u link.exe 文件:dbgheap.c行:1044 表达方式: _crtisValidHeapPointerUserData 是否不允许在VC6下导出自动ptr 通过DLL导出STL集合类是一个已知的问题 但是,我在谷歌上搜索了一下,没有看到任何关于std::auto_ptr的内容
任何解决方法?一个DLL有自己的堆,所以你必须确保你从同一个上下文中新建和删除。一个DLL有自己的堆,所以你必须确保你从同一个上下文中新建和删除。我的第一个猜测是VC9中的exe和DLL项目被设置为CRT作为共享DLL的目标,当一个或两个VC6项目都以静态CRT非dll为目标时 或者,dll和exe都针对共享CRT dll的不同版本,因此它们实际上使用2个不同的CRT
在VC6中,选中C/C++项目属性的“代码生成”类别中的“运行时库”选项。确保exe和dll都以相同的dll库选项为目标。我的第一个猜测是,VC9中的exe和dll项目设置为将CRT作为共享dll的目标,而VC6项目中的一个或两个都以静态CRT非dll为目标 或者,dll和exe都针对共享CRT dll的不同版本,因此它们实际上使用2个不同的CRT
在VC6中,选中C/C++项目属性的“代码生成”类别中的“运行时库”选项。确保exe和dll都以相同的dll库选项为目标。您违反了ODR one定义规则,而且成员函数很可能是内联的-因为它们与std::auto\u ptr的两个不同定义内联,所以您会得到未定义的行为 除此之外,正如Eddy所指出的,当auto_ptr::~auto_ptr释放保留的对象时,它将在EXE中调用运算符delete,而不是在调用运算符new的DLL中调用运算符delete。这种不匹配也会导致崩溃
一般来说,导出仅由纯虚拟函数组成的实现类接口类是非常脆弱的,导出自由工厂函数进行构造是可以的,然后不在类上使用u declspecdllexport,仅在工厂函数上。您违反了ODR one定义规则,并且成员函数很可能是内联的-因为它们是用std::auto_ptr的两个不同定义内联的,所以您会得到未定义的行为 除此之外,正如Eddy所指出的,当auto_ptr::~auto_ptr释放保留的对象时,它将在EXE中调用运算符delete,而不是在调用运算符new的DLL中调用运算符delete。这种不匹配也会导致崩溃
一般来说,导出仅由纯虚拟函数组成的实现类接口类是非常脆弱的,导出自由工厂函数进行构造是可以的,然后不在类上使用uu declspecdllexport,只在工厂函数上使用。OK。我意识到了根本原因。这是由于 DLL内存管理器混用 从DLL分配内存 返回指向EXE的指针 尝试从EXE中删除指针 如果我们在选项C/C++->代码生成->使用运行时库下动态链接到运行时库,那么步骤3只能正常工作
如果静态链接到运行时库,DLL使用的内存管理器可能与EXE使用的内存管理器不同。确定。我意识到了根本原因。这是由于 DLL内存管理器混用 从DLL分配内存 返回指向EXE的指针 尝试从EXE中删除指针 如果我们在选项C/C++->代码生成->使用运行时库下动态链接到运行时库,那么步骤3只能正常工作
如果静态链接到运行时库,DLL使用的内存管理器可能与EXE使用的内存管理器不同。为什么VC9中没有出现此问题?确定。我确实找到了VC9中没有出现问题的原因。在VC9中,我动态链接到运行时库。在VC6中,我使用静态链接。请参阅我贴出的其他答案。为什么VC9中没有出现此问题?好的。我确实找到了VC9中没有出现问题的原因。在VC9中,我动态链接到运行时库。在VC6中,我使用静态链接。请参阅我发布的其他答案。您的意思是项目设置中的运行时库选项混淆了?您的意思是项目设置中的运行时库选项混淆了?看起来像是鸡蛋和鸡的问题。出于异常安全考虑,我的本能反应是在dll函数返回的指针周围放置一个auto_ptr。但这样我就可以遇到“按不同运行时删除”问题了。@user
:尝试com_ptr_t,并在对象本身中实现释放功能。COM/DCOM/ActiveX使用此方法在模块/编译器/语言/运行时之间共享组件时发挥了巨大作用。看起来像是鸡蛋和鸡的问题。出于异常安全考虑,我的本能反应是在dll函数返回的指针周围放置一个auto_ptr。但是我可能会遇到“按不同运行时删除”问题。@user:尝试com\u ptr\t,并在对象本身中实现一个释放函数。COM/DCOM/ActiveX使用此方法在模块/编译器/语言/运行时之间共享组件时效果非常好。
// dll
#include <memory>
__declspec(dllexport) std::auto_ptr<int> get();
__declspec(dllexport) std::auto_ptr<int> get()
{
return std::auto_ptr<int>(new int());
}
// exe
#include <iostream>
#include <memory>
__declspec(dllimport) std::auto_ptr<int> get();
int main() {
{
std::auto_ptr<int> x = get();
}
std::cout << "done\n";
getchar();
}