簡體   English   中英

帶指針的C ++ Struct:構造函數和析構函數

[英]C++ Struct with pointers : constructor and destructor

我遇到一個模擬程序的問題,該程序調用DLL來執行優化任務。 在研究了這個問題一段時間之后,我認為我的問題在於我在DLL返回所需信息后用來釋放內存的析構函數。 仿真程序是在Borland C ++ Builder v6上開發的,DLL是在MS Visual C ++ 2005上開發的。

對於模擬程序(P)和DLL來交換數據,我創建了兩個結構InputCPLEXOutputCPLEX以及一個帶有兩個參數的函數optimize :一個InputCPLEX類型的對象和一個OutputCPLEX類型的OutputCPLEX 這兩種結構都在一個頭文件中聲明structures.h這屬於P項目和DLL項目。

InputCPLEXOutputCPLEX結構都有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> ,但如果我錯了,請糾正我 - 似乎很難在兩個不同的編譯器之間交換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

一年多以來,我一直在文件structures.h沒有任何構造函數或析構函數使用此代碼,因此沒有執行結構成員的初始化。 你可能已經猜到了,我不是C ++的專家,事實上它恰恰相反。 我還想強調一點,我沒有編寫大部分模擬程序,只是一些函數,這個程序是由幾個開發人員開發了10多年,結果非常混亂。

但是,直到最近,一切都運轉良好。 我決定向DLL提供更多信息(用於優化目的),因此在運行大型模擬(涉及大型數據集)時,模擬程序已經系統地崩潰。 額外的信息是兩種結構中的指針,我的猜測是程序泄漏了內存,所以我嘗試編寫構造函數和析構函數,以便可以正確管理分配給結構inputoutput的內存。 我嘗試了以下代碼,我發現在互聯網上搜索:

//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文件中的structures.h函數和析構函數,那么模擬程序仍然可以執行小型模擬,涉及小數據集。

大衛,非常感謝你的幫助。

你必須使用一致的新方法 - 刪除。 如果new[]獲取了某些內容,則應通過delete[]刪除它,如果是new - > delete by delete 在您的代碼中,您可以通過new創建inputoutput ,但通過delete[]

順便說一句,你不必在刪除前檢查指針為零。 delete處理零指針沒有問題。

我在你的代碼中看到了幾個問題:

1)內存泄漏/雙重刪除:

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

在這里,你在初始化之后立即覆蓋sol指針,並且new int[n]分配的數據被泄露。 你也可以在sol雙重刪除指針 - 在output析構函數中第二次。 var的相同問題 - 你通過顯式delete[]input析構函數刪除它兩次。

添加了帶delete析構函數后,會出現雙刪除問題,看起來就像它沒有問題。

另外,正如@Riga所提到的,你使用new[]來分配數組,但是在析構函數中delete而不是delete[] 這是不正確的,這是未定義的行為。 盡管這看起來不像崩潰的原因。 在現實世界中,大多數編譯器對內置和POD類型實現deletedelete[]沒有區別。 只有delete具有非平凡析構函數的對象數組時,才會出現嚴重問題。

2)在哪里分配output->outputData 如果在DLL中它是另一個問題,因為如果它是在用另一個編譯器實現的DLL中分配的話,通常無法安全地釋放主程序中的內存。 原因是不同的new/delete實現和主程序和DLL的運行時使用的不同堆。

你總是應該在同一側分配/釋放內存。 或者使用一些常見的低級API - 例如具有相同堆句柄的VirtualAlloc()/VirtualFree()HeapAlloc()/HeapFree()

這看起來很奇怪:

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);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM