3

DLL を呼び出して最適化タスクを実行するシミュレーション プログラムに問題があります。この問題をしばらく研究した結果、私の問題は、DLL が必要な情報を返した後にメモリを解放するために使用するデストラクタにあると思います。シミュレーション プログラムは Borland C++ Builder v6 で開発され、DLL は MS Visual C++ 2005 で開発されました。

シミュレーション プログラム (P) と DLL がデータを交換するために、2 つの構造体と、2 つの引数を取る関数を作成InputCPLEXしましOutputCPLEXた。両方の構造体は、P プロジェクトと DLL プロジェクトに属するヘッダー ファイルで宣言されています。optimizeInputCPLEXOutputCPLEXstructures.h

InputCPLEX構造体とOutputCPLEX構造体の両方intint*メンバがあるため、基本的にファイルstructures.hは次のようになります。

//structures.h
struct InputCPLEX{
  public:
  int i;
  int* inputData;
}
struct OutputCPLEX{
  public:
  int j;
  int* outputData;
}

アイデアは、シミュレーション プロセス (P の実行) に沿って、最適化問題を解決するために DLL を定期的に呼び出し、最適化問題inputDataの変数に対応する配列と、変数outputDataの最適値の配列を呼び出すというものです。などの STL コンテナを使用する方が簡単だったことはわかっていますが、vector<int>間違っていたら訂正してください。2 つの異なるコンパイラ間で STL オブジェクトを交換するのは難しいようです。

私のメインファイル(P)での様子は次のとおりです。

//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

1 年以上、ファイルstructures.hにコンストラクターまたはデストラクターなしでこのコードを使用してきたため、構造体メンバーの初期化は実行されませんでした。ご想像のとおり、私は C++ の専門家ではありません。実際はまったく逆です。また、シミュレーション プログラムのほとんどをコーディングしたわけではなく、一部の機能のみをコーディングしたことを強調しておきます。このプログラムは、複数の開発者によって 10 年以上にわたって開発されたものであり、結果は非常に厄介です。

ただし、最近まですべてが正常に機能していました。(最適化の目的で) より多くの情報を DLL に提供することにしました。その結果、大規模なシミュレーション (大規模なデータ セットを含む) を実行すると、シミュレーション プログラムが体系的にクラッシュしていました。input余分な情報は両方の構造体のポインタです。私の推測では、プログラムがメモリをリークしていたので、構造体に割り当てられたメモリoutputが適切に管理されるように、コンストラクタとデストラクタをコーディングしようとしました。インターネットを検索して見つけた次のコードを試しました:

//structures.h
struct InputCPLEX{
  public:
  int i;
  int* inputData;
  int* inputData2; // extra info
  int* inputData3; // extra info
  InputCPLEX(): i(0), inputData(0), inputData2(0), inputData3(0) {}
  ~InputCPLEX(){ 
    if (inputData) delete inputData;
    if (inputData2) delete inputData2;
    if (inputData3) delete inputData3;
  }
}
struct OutputCPLEX{
  public:
  int j;
  int* outputData;
  int* outputData2;
  int* outputData3;
  OutputCPLEX(): j(0), outputData(0), outputData2(0), outputData3(0) {}
  ~OutputCPLEX(){ 
    if (outputData) delete outputData;
    if (outputData2) delete outputData2;
    if (outputData3) delete outputData3;
  }
}

しかし、うまくいかないようです。プログラムは、ほんの少しの時間で、さらに速くクラッシュします。誰かが私のコードの問題を特定するのを手伝ってくれますか? プログラムの実行に影響を与える他の要因がある可能性があることはわかっていますが、structures.hファイル内のコンストラクターとデストラクターの両方を削除しても、シミュレーション プログラムは小さなデータ セットを含む小さなシミュレーションを実行できます。

助けてくれてありがとう、デビッド。

4

3 に答える 3

1

新しい-削除の一貫した方法を使用する必要があります。何かが取得された場合は、new[]によって削除する必要があります。- >によって削除します。あなたのコードでは、を介して作成し、削除します。delete[]newdeleteinputoutputnewdelete[]

ところで、削除する前にポインタのゼロをチェックする必要はありません。deleteゼロポインタを問題なく処理します。

于 2012-10-12T09:36:34.763 に答える
1

コードにいくつかの問題があります。

1) メモリ リーク/二重削除:

sol = new int[n];
sol = output->outputData; 

solここでは、初期化の直後にポインターをオーバーライドし、によって割り当てられたデータnew int[n]がリークされます。solまた、 のデストラクタで - 秒でポインタを二重に削除しますoutput。同じ問題-明示的およびデストラクタでvar2回削除します。delete[]input

でデストラクタを追加した後、二重削除の問題が発生しますdelete。以前は問題ではなかったようです。

また、@Rigaが述べたようnew[]に、配列を割り当てるために使用しますdeletedelete[]、デストラクタでは使用しません。これは正しくなく、未定義の動作です。これにもかかわらず、クラッシュの原因のようには見えません。現実の世界では、ほとんどのコンパイラは組み込み型と POD 型の実装deleteに違いはありません。重要なデストラクタを使用してオブジェクトを配列delete[]する場合にのみ、深刻な問題が発生する可能性があります。delete

2) どこoutput->outputDataに割り当てられますか? DLL の場合は別の問題です。別のコンパイラで実装された DLL にメモリが割り当てられている場合、通常、メイン プログラムでメモリの割り当てを安全に解除できないためです。その理由はnew/delete、メイン プログラムと DLL のランタイムで使用される実装とヒープが異なるためです。

常に同じ側でメモリを割り当て/割り当て解除する必要があります。または、いくつかの一般的な低レベル API を使用します。たとえばVirtualAlloc()/VirtualFree()HeapAlloc()/HeapFree()同じヒープ ハンドルを使用します。

于 2012-10-12T10:35:39.947 に答える
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);
于 2012-10-12T10:47:30.927 に答える