我遇到一个调用DLL来执行优化任务的模拟程序的问题。在研究了这个问题一段时间之后,我认为我的问题在于我在DLL返回所需信息后用来释放内存的析构函数。仿真程序是在Borland C ++ Builder v6上开发的,DLL是在MS Visual C ++ 2005上开发的。
对于模拟程序(P)和用于交换数据的DLL,我创建了两个结构InputCPLEX
和OutputCPLEX
以及一个带有两个参数的函数optimize
:一个类型为{的对象{1}}和InputCPLEX
类型的一个对象。两个结构都在头文件OutputCPLEX
中声明,该文件属于P项目和DLL项目。
structures.h
和InputCPLEX
结构都有OutputCPLEX
和int
成员,所以基本上文件int*
如下:
structures.h
我的想法是,在模拟过程中(P的执行),我定期调用DLL来解决优化问题,因此//structures.h
struct InputCPLEX{
public:
int i;
int* inputData;
}
struct OutputCPLEX{
public:
int j;
int* outputData;
}
是与我的优化问题中的变量对应的数组{{1是我的变量的最佳值数组。我知道使用STL容器会更容易,例如inputData
,但是如果我错了,请纠正我 - 似乎很难在两个不同的编译器之间交换STL对象。
以下是我的主文件中的内容(在P中):
outputData
一年多以来,我一直在文件vector<int>
中使用此代码而没有任何构造函数或析构函数,因此未执行结构成员的初始化。你可能已经猜到了,我不是C ++的专家,事实上它恰恰相反。我还想强调一点,我没有编写大部分模拟程序,只是一些函数,这个程序是由几个开发人员开发了10多年,结果非常混乱。
然而,直到最近,一切都运转良好。我决定向DLL提供更多信息(用于优化目的),因此在运行大型模拟(涉及大型数据集)时,模拟程序已经系统地崩溃。额外的信息是两个结构中的指针,我的猜测是程序泄漏了内存,所以我尝试编写构造函数和析构函数,以便分配给结构//main.h
InputCPLEX* input;
OutputCPLEX* output;
int* var;
int* sol;
//main.cpp
[...] //lots of code
input = new InputCPLEX;
output = new OutputCPLEX;
int n = X; //where X is an integer
var = new int[n];
[...] //some code to fill var
input->i = n;
input->inputData = var;
optimize(input,output); //calls the DLL
int m = output->j;
sol = new int[n];
sol = output->outputData;
[...] //some code to use the optimized data
delete[] var;
delete[] sol;
delete input;
delete output;
[...] //lots of code
和structures.h
的内存可以是妥善管理。我尝试了下面的代码,我发现在网上搜索:
input
但它似乎不起作用:程序在很短的时间后崩溃得更快。有人可以帮我识别代码中的问题吗?我知道可能有其他因素影响我的程序的执行,但如果我删除output
文件中的构造函数和析构函数,那么模拟程序仍然能够执行小型模拟,涉及小数据集。
非常感谢你的帮助, 大卫。
答案 0 :(得分:1)
你必须使用一致的新方法 - 删除。如果new[]
获得了某些内容,则应delete[]
删除该内容,如果new
- >按delete
删除。在您的代码中,您可以input
创建output
和new
,但可以通过delete[]
删除。
顺便说一句,你不必在删除前检查指针为零。 delete
处理零指针没有问题。
答案 1 :(得分:1)
我在您的代码中看到了几个问题:
1)内存泄漏/双重删除:
sol = new int[n];
sol = output->outputData;
这里你在初始化之后立即覆盖sol
指针,并且new int[n]
分配的数据被泄露。你也可以在sol
中双重删除指针 - 在output
的析构函数中第二次删除指针。与var
相同的问题 - 您通过显式delete[]
和input
的析构函数将其删除两次。
在使用delete
添加析构函数后,会出现双删除问题,看起来就像它没有问题一样。
同样@Riga提到你使用new[]
来分配数组,但在析构函数中使用delete
而不是delete[]
。这是不正确的,这是未定义的行为。尽管这看起来不像崩溃的原因。在现实世界中,大多数编译器对于内置和POD类型实现delete
和delete[]
没有区别。只有当delete
具有非平凡析构函数的对象数组时,才会出现严重问题。
2)分配output->outputData
的位置?如果在DLL中它是另一个问题,因为如果它是在用另一个编译器实现的DLL中分配的话,通常无法安全地释放主程序中的内存。原因是不同的new/delete
实现和主程序和DLL的运行时使用的不同堆。
你总是要在同一侧分配/释放内存。或者使用一些常见的低级API - 例如<{1}}或VirtualAlloc()/VirtualFree()
具有相同的堆句柄。
答案 2 :(得分:0)
这看起来很奇怪:
int m = output->j;
sol = new int[n];
sol = output->outputData;
据我所知,你以m为单位返回大小但是用n分配 然后通过将指针(sol)设置为outputData来覆盖数组 我认为你的意思是:
int m = output->j;
sol = new int[m];
memcpy(sol,output->outputData,sizeof(int)*m);