2011-07-25 33 views
3

我想在全局範圍內定義一個包含一些動態分配數組的類。當調用類的構造函數時,程序無法訪問通過參數文件讀取的用戶定義參數(即模擬中的年數),因此無法將內存分配到適當的大小。我的想法是在類中的私有函數內分配內存,然後使用析構函數釋放它。一些示例代碼:如果一個析構函數使用C++中的私有函數分配內存,它可以釋放內存嗎?

class Simulation{ 
private: 
    int initial_call; //a flag used to initialize memory 
    double *TransferTracker; 
public: 
    Simulation(); 
    ~Simulation(); 
    void calc(); 
}; 

Simulation simulator; //global instance of Simulation 

Simulation::Simulation() 
{ 
    initial_call = 1; 
} 
Simulation::~Simulation() 
{ 
    //when calling the destructor, though, the address is 
    //0xcccccccc and the following attempt to delete produces 
    //the compiler error. 
    delete [] TransferTracker; //see error 
} 
void Simulation::calc() 
{ 
    for (int i = 0; i < num_its; i++) 
    { 
     if (initial_call) 
     { 
      TransferTracker = new double [5]; 
      //The address assigned is, for example, 0x004ce3e0 
      initial_call = 0; 
     } 
    } 
    //even if this calc function is called multiple times, I see 
    //that the address is still 0x004ce3e0. 
} 

我從上面的代碼片段收到的錯誤是:

Unhandled exception at 0x5d4e57aa (msvcr100d.dll) in LRGV_SAMPLER.exe: 0xC0000005: Access  
violation reading location 0xccccccc0. 

該錯誤是有道理的,因爲我進入析構函數時檢查TransferTracker的存儲器地址。我的問題是,爲什麼我們在進入析構函數時失去了地址?這可能與模擬器是全球性的事實有關;如果這個類不是全球性的,這個範例似乎工作得很好。我是新來的面向對象編程,所以任何幫助表示讚賞!

編輯:這基本上是我的錯誤,並得到了答案的幫助。出現了兩個問題:(1)指針從未設置爲NULL,因此在嘗試刪除未分配的指針時產生混淆。 (2)在我的範圍內,實際上有兩個班的實例,這是我的錯誤。在最終的代碼中,將只有一個實例。感謝大家!

+0

你的析構函數如何被調用?它是全球性的,所以它只會被稱爲obn程序退出權限? –

+0

是的,這是正確的;它在程序出口處。 – Joe

回答

3

您必須初始化構造函數中的實例變量TransferTracker0的價值。你遇到的問題是Simulation類的破壞,實際上沒有分配動態內存到TransferTracker

在析構函數中用空指針調用delete[]是安全的。問題是,如果你不給TransferTracker的值,它可能有任何未定義的值,這將導致嘗試釋放與delete[]釋放的麻煩。

編輯

根據您的編輯,你如何確保有是Simulation類只有一個實例?這與你的內部版本中包含多個.o文件等有關。

+0

查看我的編輯;我意識到這看起來像我原來的問題,但在calc中的分配被調用,它似乎工作。 – Joe

+0

據我所知,我只宣佈了一次。這是對這個問題的一個愚蠢的答案嗎? – Joe

+0

感謝您的幫助;我接受你的答案,因爲它討論了該課程的多個實例。我還編輯了我的問題來討論我愚蠢的錯誤。 – Joe

1

我懷疑原因是當你沒有調用calc()函數時你的析構函數被調用,因此內存還沒有被分配。

你想放置一個「後衛」,以確保你已經分配了內存,然後再試圖釋放內存爲TransferTracker

+0

查看我的編輯;我意識到這看起來像我原來的問題,但在calc中的分配被調用,它似乎工作。 – Joe

+0

@Joe:你確定被破壞並導致問題的實例實際上是分配完成的實例嗎? –

+0

這是一個很好的問題,保羅,我幾乎可以肯定只有一個例子,另一個不知道怎麼會出現?這是否有嘗試擁有全球課堂實例的危險? – Joe

5

初始化指針爲NULL(0)

Simulation::Simulation() : TransferTracker(NULL) 
{ 
    initial_call = 1; 
} 
Simulation::~Simulation() 
{ 
    //when calling the destructor, though, the address is 
    //0xcccccccc and the following attempt to delete produces 
    //the compiler error. 
    if(TransferTracker) delete [] TransferTracker; //see error 
    TransferTracker = NULL; 
} 

這樣,當你想刪除它,你可以請檢查是否與否已初始化。這是最好的做法,這樣做始終,不僅在建築

編輯:

void Simulation::calc() 
{ 
    for (int i = 0; i < num_its; i++) 
    { 
     if (initial_call) 
     { 
      if(TransferTracker) delete [] TransferTracker; 
      TransferTracker = new double [5]; 
      initial_call = 0; 
     } 
    } 
} 
+1

您不必測試'TransferTracker'是否爲'0'。在這種情況下'delete'也可以工作。 –

+0

在調用'delete'運算符之前,不需要檢查NULL,它會爲您執行。但是在調用delete之後將其設置爲NULL是一個好主意,以便在析構函數被調用兩次的情況下保護自己免於做瘋狂的事情。 – 2011-07-25 18:33:27

+4

如果析構函數被兩次調用瘋狂的事情已經發生。 – AJG85

相關問題