为什么不要在DLL模块内分配内存而在调用模块释放?
来源:互联网 发布:linux输入中文乱码 编辑:程序博客网 时间:2024/05/17 20:30
很多初学编程的朋友都会碰到这样的问题:有时需要在一个Dll中获取一个字符串或者一个数组并返回给调用程序。
在这个问题中,内存分配成了一个费脑筋的问题。如果在调用程序中分配内存,不知道该分配多大。如果在Dll内部分配内存,则Dll无法释放。于是很多朋友都尝试过第三种解决方案:在Dll中分配内存,然后在调用程序中释放。不幸的是,通常会得到这个错误:
void GetString(char** ppStr, int& len){len = 100;char* pStr = new char[len];//do something fill pStr//for examplepStr[0] = 'a';pStr[1] = 'b';pStr[2] = 'c';pStr[3] = '\0';*ppStr = pStr;}Main:
HMODULE hModule = LoadLibrary(Dll路径);if(hModule){GetString pFuncGetStr = (GetString) GetProcAddress(hModule, "GetString");if(pFuncGetStr){char** ppStr = new char*();int len = 0;pFuncGetStr(ppStr, len);printf("%s", *ppStr);printf("%d", strlen(*ppStr));delete [] *ppStr;delete ppStr;ppStr = NULL;}}
而奇怪的是,如果将Dll 中的函数复制粘贴到调用程序中,使用同样的调用方式就没有问题。为什么?
看一下MSDN上对_CrtisValidHeapPointer的解释:Verifies that a specified pointer is in the local heap (debug version only). 主要意思是,_CrtisValidHeapPointer是用来验证一个指针指向的内存是否是分配在本地堆中的。每一个C运行库的实例都维护着自己的本地堆,在一个C运行库中分配的堆内存,在另一个C运行库的实例中使用_CrtisValidHeapPointer验证就会返回FALSE。默认情况下,VC编译器(VC6.0)创建的Dll工程使用静态链接(Setting--C++选项卡--CodeGeneration) Debug MultiThreaded(Debug版本),Console的工程也使用静态链接,程序运行的时候,是存在两个C运行库的实例的。在Dll中的C运行库分配的内存在Main函数中释放的时候,会使用_CrtisValidHeapPointer检查这个内存(Debug版本),这时候返回的当然是FALSE,于是断言失败,显示出上边的失败提示。
为了验证这个结论,我们把C运行库的 链接 方式都改为动态链接(Debug MultiThread Dll),重新编译后再次运行就没有问题了。
明白了这一点以后,这个问题的解决方案也就有了:第一种解决方案是,Dll分配Dll释放。给DllGetString配备一个DllFreeString。第二种解决方案是,调用者分配,调用者释放。那么如何确定分配内存大小呢?当然是也是询问Dll得到。参考Windows的很多API,可以这样定义: int GetString(char** ppStr, int& len);如果调用成功返回值等于len,如果返回值大于len,说明内存分配的不够大,需要重新分配。使用的时候需要两次调用,先用一个试探值得到所需内存,再分配内存,例子如下:
char** ppStr = new char*(); int len = 0; int nret = GetString(ppStr, len); if(nret > len) { len = nret; *ppStr = new char[len]; nret = GetString(ppStr, len); if(nret == len) { printf("%s", *ppStr); } delete [] *ppStr; delete ppStr; ppStr = NULL; }
第三种解决方案就是像上边那样将Dll和主程序的C运行库都该为动态连接,但是这只是不得已的一种补救做法,一般情况下还是应该使用正确的设计。
事实上,即使只在同一个模块中调用,多数情况下也应该遵循谁分配谁释放的原则。这样的代码易于阅读和维护。谁知道哪一天哪一个函数可能会被移动到一个独立的模块中呢?
- 为什么不要在DLL模块内分配内存而在调用模块释放?
- 如何在Dll中分配内存,而在调用程序里释放
- 在一个模块中分配的内存在另外一个模块释放?
- Windows编程 在一个模块中分配的内存在另外一个模块释放?
- Windows编程 在一个模块中分配的内存在另外一个模块释放?
- 在一个模块中分配的内存在另外一个模块释放
- 在不同模块分配和释放内存时出错的原因
- 在不同模块分配和释放内存时出错的原因
- 关于Cross-Dll问题(在不同的模块之间申请和释放内存)
- 在Dll中申请了内存,现在想在Exe模块中释放这部分内存.但不成功.
- DLL分配的内存如何在EXE里面释放
- DLL分配的内存如何在EXE里面释放
- 在linux中 应用程序如何调用模块内的函数
- 在linux中 应用程序如何调用模块内的函数
- 在linux中应用程序如何调用模块内的函数
- 在linux中 应用程序如何调用模块内的函数
- 在linux中应用程序如何调用模块内的函数
- 在模块内对内存的分配过早优化的缺点
- Vim最佳实践
- 虚拟机慢的解决方案
- 问题一百一十二:C语言合法标识符(2)
- 三进制转十进制 不同进制的数值间的转换是软件开发中很可能会遇到的常规问题。
- CentOS6.4安装samba后windows不能访问
- 为什么不要在DLL模块内分配内存而在调用模块释放?
- Aspose.Words操作word excel ppt说明
- 编程珠玑(2)第十章学习笔记
- 代理代码改进
- JAVA技术小提高(一)JAVA概述(一)
- CHttpFile
- .net学习笔记(1)
- Java如何防止数据进行科学计数
- phpdocumentor