2011-12-18 31 views
2

我有以下代碼:爲什麼不在異常未被捕獲到時調用析構函數?

#include <iostream> 
#include <vector> 
#include <tr1/memory> 

struct FooError {}; 

struct Foo 
{ 
    ~Foo() { std::cerr << "~Foo() executed" << std::endl; } 
    explicit Foo(unsigned int index) { if (5 == index) throw FooError(index); }; 
}; 


int main() { 
    typedef std::tr1::shared_ptr<Foo> FooPtr; 
    std::vector<FooPtr> foos; 
    for (unsigned int index = 0; index < 20; ++index) 
    { 
     try 
     { 
      foos.push_back(FooPtr(new Foo(index))); 
     } 
     catch (const FooError&) 
     { 
      std::cerr << "FooError caught" << std::endl; 
     } 
    } 
} 

我看到一組執行~Foo()當有try{} catch{}塊。如果沒有異常處理程序,則不會打印任何內容。這是否意味着在處理異常時調用堆棧分配對象的析構函數?還是沒有打印,因爲std :: cerr緩衝問題?

回答

1

如果發現異常,將調用釋放器來清理內存。如果你沒有發現異常,應用程序就會退出。

一個vector實際上將它所有的數據存儲在堆上;這就是爲什麼它可以調整大小。您可以將堆棧中的數據視爲指向堆中內存的指針(對您來說是隱藏的)。

+1

+1。我沒有意識到OP在談論沒有try/catch時的情況,認爲這是關於何時拋出異常的問題。 – 2011-12-18 17:22:43

+1

但是我現在刪除的答案仍然很重要 - 'Foo'沒有堆棧分配。 – 2011-12-18 17:23:20

+0

我想知道爲什麼沒有堆棧解繞發生。如果有幾個塊級別,並且在下級錯誤被捕獲,那麼我會因爲FooPtr的aint釋放而導致內存泄漏? – bananov 2011-12-18 17:31:33

3

程序的範圍展開,無論是通過正常執行還是通過try/throw/catch,只有當應用程序從main返回時才退出。如果應用程序通過異常退出(或通過abort()terminate()),則不會發生退繞,也不會調用析構函數。

這屬於自動和靜態對象。

+0

如果我們發現在發生點和main()返回點之間的中途發生了異常,但隨後重新拋出它,那麼析構函數是不是隻會調用到我們發現異常的地方? – jrok 2011-12-18 17:50:19

+1

「不放卷」 - 一般來說它是由實現定義的,不管它是否發生,在這種情況下不是。 – 2011-12-18 19:15:50

+0

@SteveJessop:你可以查看這個例子:http://ideone.com/X7Hv8?這是否意味着它的實現定義了foo的構造函數是否會被調用?或者'foo'總會被毀滅? – jrok 2011-12-18 19:23:50

2

在循環之後,在程序退出之前,正在調用析構函數(來自向量)。

如果您沒有發現異常,那麼會調用terminate來中止程序而不調用析構函數。

+1

「沒有調用析構函數」 - 這是這個實現上發生的事情,但不保證它們不會被調用(C++ 11中的15.3/9)。 – 2011-12-18 19:15:18

5

下面是來自C++ 03標準的細節。

  • 從15.3/9處理異常

    如果程序中沒有找到匹配的處理程序,函數終止()被調用;

  • 從18.6.3異常終止:

    實施的默認terminate_handler調用abort()。

  • 而從3.6.3/4終止:

    撥打<cstdlib>聲明的功能void abort();結束程序,而不執行析構的自動或靜態存儲持續時間的對象和不調用傳遞給功能的atexit()。

所以這就是爲什麼你 foos對象不被破壞(它具有靜態存儲持續時間)。但是,即使你改變它,這樣它的(具有自動持續時間)的局部變量,可能不解決問題(強調):

所以對於static duration對象,析構函數沒有被執行,除非你改變了終止處理程序(可能會呼叫exit()而不是abort())。然而,用於自動對象,但仍可能出現的問題(強調):

15.5.1/1 terminate()功能

在情況下沒有匹配的處理器被發現,它是 implementation-定義是否在 terminate()被調用之前堆棧是否展開。在所有其他情況下,在調用terminate()之前,堆棧不應被解開。

+0

我不認爲「foos」有靜態存儲時間,我認爲這個定義在'main'函數中。 – 2011-12-18 19:17:31

+0

@Steve - 我認爲你是對的,對我來說是一個誤讀。我已經更新了答案。 – 2011-12-18 19:26:15

相關問題