【发布时间】:2016-02-02 13:55:45
【问题描述】:
我有以下代码:
在 DLL1 中:
在 .h 文件中:
class MyClass
{
public:
MyClass();
private:
std::string m_name;
};
class __declspec(dllexport) Foo
{
private:
struct Impl;
Impl *pimpl;
public:
Foo();
virtual ~Foo();
};
struct Foo::Impl
{
std::vector<MyClass> m_vec;
std::vector<MyClass> &GetVector() { return m_vec; };
};
在 .cpp 文件中:
Foo::Foo() : pimpl ( new Impl )
{
}
Foo::~Foo()
{
delete pimpl;
pimpl = NULL;
}
[编辑]
在 DLL2 中
在.h中
class Bar : public Foo
{
public:
Bar();
virtual ~Bar();
};
在 .cpp 中:
Bar::Bar()
{
}
Bar::~Bar()
{
}
在 DLL3 中:
extern "C" __declspec(dllexport) Foo *MyFunc(Foo *param)
{
if( !param )
param = new Bar();
return param;
}
在主应用程序中:
void Abc::my_func()
{
Foo *var = NULL;
// loading the DLL3 and getting the address of the function MyFunc
var = func( var );
delete var;
}
现在,我假设复制构造函数应该是私有的,因为复制 Foo 和 Bar 对象没有意义。
现在我的问题是:Bar 是否也应该有复制构造函数和赋值运算符? [/编辑]
注意 MyClass 没有被导出,也没有析构函数。
这通常是你编写代码的方式吗?
问题是我在 Windows 上崩溃了(8.1 + MSVC 2010,如果重要的话)。 如果需要,我可以发布更多代码,但现在只是想确保我没有做明显错误的事情。
崩溃发生在我退出 Base 析构函数并且堆栈跟踪显示:
ntdll.dll!770873a6() [下面的帧可能不正确和/或 丢失,没有为 ntdll.dll 加载符号] ntdll.dll!7704164f()
ntdll.dll!77010f01() KernelBase.dll!754a2844()
dll1.dll!_CrtIsValidHeapPointer(const void * pUserData) 行 2036 C++ dll1.dll!_free_dbg_nolock(void * pUserData,int nBlockUse) 第 1322 行 + 0x9 字节 C++ dll1.dll!_free_dbg(void * pUserData, int nBlockUse) 第 1265 行 + 0xd 字节 C++ dll1.dll!operator delete(void * pUserData) 第 54 行 + 0x10 字节 C++ dll1.dll!Foo::`向量删除析构函数'() + 0x65 字节 C++
谢谢。
更新:
即使我将以下代码放入
extern "C" __declspec(dllexport) Foo *MyFunc(Foo *param)
{
param = new Bar();
delete param;
return param;
}
程序在同一个地方的delete param操作还是crash。
看起来 std::vector 的析构函数是在调用 Foo 的析构函数之后调用的。是不是应该是这样的?
更新2:
在调试器下仔细运行后,我发现崩溃发生在“void operator delete(void *pUserData);”内部。 pUserData 指针的地址为“param”。
DLL1 是用这个构建的:
C++
/ZI /nologo /W4 /WX- /Od /Oy- /D "WIN32" /D "_DEBUG" /D "_LIB" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /Fp"Debug\dll1.pch" /Fa"Debug\" /Fo"Debug\" /Fd"Debug\vc100.pdb" /Gd /analyze- /errorReport:queue
图书管理员 /OUT:"C:\Users\Igor\OneDrive\Documents\dbhandler1\docview\Debug\dll1.lib" /NOLOGO
DLL2 是用以下方式构建的:
C++
/I"..\dll1\" /Zi /nologo /W4 /WX- /Od /Oy- /D "WIN32" /D "_USRDLL" /D "DLL_EXPORTS" /D "_DEBUG" /D "_CRT_SECURE_NO_DEPRECATE=1" /D "_CRT_NON_CONFORMING_SWPRINTFS=1" /D "_SCL_SECURE_NO_WARNINGS=1" /D "_UNICODE" /D "MY_DLL_BUILDING" /D "_WINDLL" /D "UNICODE" /Gm- /EHsc /RTC1 /MTd /GS /fp:precise /Zc:wchar_t /Zc:forScope /GR /Fp"vc_mswud\dll2\dll2.pch" /Fa"vc_mswud\dll2\" /Fo"vc_mswud\dll2\" /Fd"vc_mswud\dll2.pdb" /Gd /analyze- /errorReport:queue
Linker
/OUT:"..\myapp\vc_mswud\dll2.dll" /INCREMENTAL /NOLOGO /LIBPATH:"..\docview\Debug\" /DLL "dll1.lib" "kernel32.lib" "user32.lib" "gdi32.lib" "comdlg32.lib" "winspool.lib" "winmm.lib" "shell32.lib" "shlwapi.lib" "comctl32.lib" "ole32.lib" "oleaut32.lib" "uuid.lib" "rpcrt4.lib" "advapi32.lib" "version.lib" "wsock32.lib" "wininet.lib" /MANIFEST /ManifestFile:"vc_mswud\dll2\dll2.dll.intermediate.manifest" /ALLOWISOLATION /MANIFESTUAC:"level='asInvoker' uiAccess='false'" /DEBUG /PDB:"vc_mswud\dll2.pdb" /PGD:"C:\Users\Igor\OneDrive\Documents\myapp\dll2\vc_mswud\dll2.pgd" /TLBID:1 /DYNAMICBASE /NXCOMPAT /IMPLIB:"vc_mswud\dll2.lib" /MACHINE:X86 /ERRORREPORT:QUEUE
有人发现我的库的构建方式有任何问题吗?
【问题讨论】:
-
我希望你永远不要复制
Foo,因为编译器生成的复制构造函数会执行pimpl的浅拷贝,导致双重删除。 -
你没有遵循三法则。现在,除此之外,我认为您应该展示您如何使用
Foo。目前尚不清楚您是否遵循内存分配和 DLL 释放指南。具体来说,分配Foo的人应该释放Foo。是这样吗? -
这不是问题,但是在
Foo的析构函数中将pimpl设置为NULL是没有意义的。对象正在消失,所以pimpl也会消失。 -
您可能需要发布更多代码。您发布的代码中没有
Base,因此退出其析构函数的失败很难解决。 -
我使用发布的代码创建了一个小项目并且没有崩溃。意味着您与我们共享的代码中可能没有其他内容。顺便说一句,我向您推荐相同的(根据您的帖子制作小项目)。也许它会帮助您更快地发现问题。
标签: c++ dll pimpl-idiom