2009-08-04 12 views
1

感謝所有的響應C++:處理資源,如果構造函數可能會拋出異常(參考FAQ 17.4]

我重新格式化我的問題,瞭解成員指針的狀態下,方含類構造函數拋出異常後

再我的例子類:)

class Foo 
{ 
public: 
    Foo() 
    { 
     int error = 0; 
     p = new Fred; 

     throw error; // Force throw , trying to understand what will happen to p 
    } 

    ~Foo() 
    { 
     if (p) 
     { 
      delete p; 
      p = 0; 
     } 
    } 
private: 
    Fred* p; 
}; 

int main() 
{ 
     try 
     { 
     Foo* lptr = new Foo; 
     } 
     catch (...) 
     {} 
} 

類FOO的consturctor會拋出一個異常,爲一些隨機的原因。我知道foo的desturctor永遠不會被調用,但在這種情況下,p的析構函數會被調用嗎?

它使p作爲boost智能指針而不是fred的原始指針有什麼區別。

謝謝。

+0

這是我的錯。請原諒我沒有正確格式化我的問題。 我想了解,如果容器類的構造函數由於某些隨機原因而失敗,是否會調用成員指針的析構函數。 也有什麼區別,它使p作爲升壓智能指針比fred的原始指針。 – mithuna 2009-08-04 23:39:19

+1

如果Foo的構造函數的主體拋出,則將調用Foo所有成員的析構函數。然而,成員p是一個Fred *,指針的「析構函數」從不做任何事情(相當於:它們沒有析構函數,我不記得確切的語言)。所以它是否被稱爲是沒有實際意義的問題。 Fred的析構函數不會被調用。如果p是一個shared_ptr,那麼可以通過'new'成功創建Fred,然後使用p的構造函數拋出。在這種情況下,Fred類的析構函數將被shared_ptr的構造函數調用,作爲其合約的一部分。 – 2009-08-04 23:59:25

回答

5

有一個similar question here涵蓋了你的要求。

在這種情況下,如果new的調用失敗,則指針的內存將保證被釋放。如果調用成功,並且構造函數在此之後拋出,則會發生內存泄漏。

該類的析構函數將不會被調用,因爲該對象從未完全構造。有兩種方法可以解決這個問題。

1)

都有例外完全在構造函數中進行管理:

class Foo 
{ 
public: 
    Foo() 
    try 
    { 
     p = new p; 

     throw /* something */; 
    } 
    catch (...) 
    { 
     delete p; 

     throw; //rethrow. no memory leak 
    } 
private: 
    int *p; 
}; 

2)

或者使用智能指針。當輸入構造函數時,其所有成員都已構建。因爲當一個構造函數拋出,並且構造了對象成員時,它們必須被破壞。而一個智能指針修復了這個問題:

class Foo 
{ 
public: 
    Foo() : 
    p(new int) 
    { 
     throw /* something */; 
    } 
private: 
    std::auto_ptr<int> p; 
}; 
+0

解決問題的第三種方法是兩階段建設。第一階段:從不拋出的常規構造函數。第二階段:可能拋出代碼。施工階段很容易集成在靜態工廠方法中。這種模式在例如Symbian C++代碼。 http://developer.symbian.com/main/support/code_clinic/clinic_june2008/ – laalto 2009-08-05 06:44:16

2

如果從未分配過,則不應該。

但不是NULL通過新的不良分配返回,你會得到一個異常std :: bad_alloc。

NULL如果無法進行分配,則由C malloc返回。

你也是正確的,如果一個對象沒有完全構建,它不會被破壞。因此,如果您在構造函數中的堆上有成功的分配,然後拋出異常,則會導致內存泄漏。

你也可以考慮有一個殭屍狀態,而不是拋出一個異常。一些標準的C++庫會這樣做。在這種情況下,對象不處於有效狀態,可以通過另一種方法檢查它是否處於有效狀態。

雖然通常在構造函數中拋出異常是最好的。

See my answer here for an extended discussion

1

如果p的內存分配失敗,將不會調用p的析構函數。

1

這個問題真的沒有任何意義。 new Fred();將永遠不會返回NULL。它只會成功創建一個Fred對象,或者拋出一個異常。如果它拋出一個異常,Fred對象將永遠不存在,所以它的析構函數將不會被調用。

+2

如果事先調用了set_new_handler(NULL),或者使用了'new(nothrow)','new'可以返回NULL。 – 2009-08-04 23:39:00

+0

@RemyLebeau調用set_new_handler(NULL)不會使其返回NULL而不是拋出。根據http://www.cplusplus.com/reference/new/set_new_handler/'如果這是一個空指針,新的處理函數被重置爲none(而bad_alloc被拋出)' – 2013-07-12 14:14:16

+0

@Occulta:Borland/CodeGear/Embarcadero編譯器以我描述的方式實現它。 [參見文檔](http://docwiki.embarcadero.com/RADStudio/XE4/fr/Set_new_handler_function):「要保留 新的傳統版本,**不會拋出 異常**,您可以使用set_new_handler( 0)。」 – 2013-07-12 14:46:02

相關問題