2011-10-10 133 views
5

下面的示例會留下可能的內存泄漏,因爲析構函數不會在其構造函數運行期間處理異常的對象運行。我在哪裏處理這個內存泄漏?在構造函數中捕獲異常

#include <exception> 

class MyClass { 

public: 
     MyClass() 
     { 
      c = new char[5]; 
      throw std::runtime_error("test"); 
     } 

     ~MyClass() 
     { 
      delete[] c; 
     } 

private: 
    char *c; 
}; 

int main() 
{ 
    try 
    { 
     MyClass Obj; 

    } 
    catch (std::runtime_error) 
    { 

    } 
} 

回答

5

您最好使用RAII,在這種情況下,智能指針是具體的。

或者,您可以使用Two Phased Construction策略。

你總是可以在構造函數主體中使用封閉的try-catch塊,並顯式調用刪除所有你動態分配的資源,但想到你有動態分配的資源數量的情況下,顯式地保持跟蹤變得非常混亂在您需要在catch中取消分配的每個資源中,在這種情況下,RAII爲您提供了最佳解決方案,因爲這樣每個資源都會隱式地處理自己的重新分配,並且不需要具有跟蹤每個資源的開銷。

boost::scoped_ptrstd::tr1::scoped_ptr適合這種情況,而不是任何原始指針。

+2

什麼要求這個downvote? RAII是解決這個問題的最好方式,如果有人說不是這樣的話。如果您覺得對Downvote負責任,那麼有責任對我們解釋爲什麼?如果你不能&只是*感覺*這是錯誤的,那麼你沒有足夠的資格進行downvoting,讓其他人這樣做。 –

+0

是基於C++ 11相關內容的解決方案嗎? – user103214

+0

不,這是C++ 03。 –

6

在構造函數中捕獲異常,整理(釋放你的內存),然後拋出異常而沒有內存泄漏。

+0

當我在構造函數中拋出內存泄漏的異常時,析構函數從未被調用過。這有什麼理由嗎? – user103214

+1

@ user974191:對象構造不完整,直到構造函數的結束括號。析構函數僅針對已完成的對象調用。如果構造函數沒有完全執行,則該對象不存在,因此不會調用析構函數。 –

1

你能趕上在構造函數體中的例外,做你的需要清理,然後再次拋出與throw;

也就是說,異常和內存手工處理的例外時沒有很好地一起去。使用自動管理c成員的內存的對象(例如std::string,std::vector<char>,std::unique_ptr<char[]>等)將會更好。如果你正在寫一個像上面這樣的類,那麼你只需要明確地管理內存,其目的正是爲了照顧內存。

4

一種方法是throw條件異常在構造函數的開頭,然後分配內存。

MyClass() 
    { 
    if(<condition>) 
     throw std::runtime_error("test"); 
    c = new char[<SIZE>]; 
    } 

另一種方法是使用特殊的語法try-catch()封閉的構造:

MyClass() 
    try { 
    c = new char[5]; 
    throw std::runtime_error("test");; 
    } 
    catch(std::runtime_error e) { 
    delete[] c; 
    } 

Demo