跨dll使用template/STL需要注意的问题
dll:
extern "C"
{
__declspec(dllexport) void PrintVector(const vector<int> v)
{
copy(v.begin(), v.end(), ostream_iterator<int>(cout, " "));
}
}
exe:
typedef void (* FUNC)(const vector<int>);
int main()
{
HMODULE hModule = LoadLibrary("VectorDll.dll");
if (hModule)
{
FUNC fun = (FUNC)GetProcAddress(hModule, "PrintVector");
vector<int> v(10, 1);
fun(v);
}
return 0;
}
上面代码存在严重的问题,运行时会崩溃:
在windows核心编程中明确的说了在dll中如果申请了内存空间,就一定要在dll中释放这块内存空间。
在exe和dll都静态链接到C/C++运行时库的时候,exe和dll都有各自的堆(heap)空间,所以各自申请的内存需要各自释放。
上面代码将参数改成 const vector<int> & 就可以正常运行。
但是如果exe中的vector版本和dll中vector的版本不同,问题又会出现,并且这些是未知的问题。
所以在dll函数接口中尽量使用基本数据类型。
关于exe和dll内存分配:
http://www.codeguru.com/forum/showthread.php?t=229394
http://www.gamedev.net/community/forums/topic.asp?topic_id=289896
http://blog.csdn.net/dotphoenix/archive/2009/07/14/4348686.aspx
http://blog.sina.com.cn/s/blog_60d705b10100g4ou.html
http://hi.baidu.com/honey%BC%A6/blog/item/8780d1f918976ed5b58f310f.html
关于dll和template/STL:
DLL分配的内存如何在EXE里面释放
总结下面几个要点:
1. 保证内存分配和清除的统一性:如果一个DLL提供一个能够分配内存的函数,那么这个DLL同时应该提供一个函数释放这些内存。数据的创建和清除应该在同一个层次上。
曾经遇到过这样的例子:在dll中分配了一块内存,通过PostMessage将其地址传给应用。然后应用去释放它,结果总是报异常。
2.如果exe用 MFC Appwizard方式生成, dll用win32方式生成,则运行时会出现错误。进一步用单步跟踪,发现mfc方式和win32方式下的new操作符是用不同方式实现的,源程序分别在VC目录的文件 Afxmem.cpp和new.cpp中。有兴趣的话可以自已跟踪一下。
因为dll输出函数后,并不知道是哪一个模拟调用它,因此new和delete配对时最好在一个文件中,这样可以保证一致性。
3. 问题主要在于DLL和EXE主程序中分配内存的堆不一样,你可以不用new和delete,而是用
1) ::HeapAlloc(::GetProcessHeap(),...)和::HeapFree(::GetProcessHeap(),...)
2) ::GlobalAlloc()和::GlobalFree()
这两对API,这样无论在DLL中还是在主程序中都是在进程默认堆中分配,就不会出错了。
4. 还有一个办法,就是把dll的Settings的C/C++选项卡的Code Generation的Use Run-time liberary改成Debug Multithreaded DLL,在Release版本中改成Multithreaded DLL,就可以直接使用new和delete了。不过MFC就不能用Shared模式了。