2016-11-04 41 views
1

比如我有一個簡單的代碼:C++ new操作符是如何工作的內部

class B 
{ 
}; 

class A 
{ 
    B b; 
    public: 
    A() 
    { 
     throw 1; 
    } 
}; 

int main() 
{ 
    A* a = 0; 
    try 
    { 
     a = new A; 
    } 
    catch (int) 
    { 
    } 
} 

構造函數拋出異常,那麼析構函數不會被調用。但是B的析構函數會被調用。堆中的內存不會被分配。我的問題如何在內部工作?首先會是:構造A還是在堆中分配內存?那麼,如果分配是第一個,如果存在異常,將如何解除分配?別的,如果構建A是第一個,它是如何應對堆的?

回答

4
  1. 內存已分配。
  2. A的構造函數被調用。
  3. A的構造函數調用B的構造函數。
  4. A的構造函數拋出。
  5. 作爲標準異常處理過程的一部分,B的析構函數被調用(RAII在工作中)。
  6. 堆棧展開給調用者(main)。
  7. 內存解除分配(因爲對象未成功構建)。

A的析構函數未被調用,因爲對象沒有被完全構造。然而,分別爲的成員仍然被破壞。

內存自動釋放的方式與控制離開塊時局部變量被銷燬的方式幾乎相同。如果您熟悉Java和/或C#,請將其視爲看不見的try-finally構造。或者一系列這樣的結構。

+0

謝謝,你的評論很好,但我需要更多的信息。在堆內存中提供析構函數的機制是什麼? – M90

+0

@ M90,我認爲這個機制是特定於實現的。就像我說的,一個看不見的'try-finally'塊。就像,如果出現問題,控制權轉移到一些自動生成的代碼,負責照顧任何需求,然後繼續傳播異常。編譯你的代碼到程序集中,看看它*真正的作用,如果你真的好奇。 –

+1

@ M90另請參見草藥薩特的[構造失敗...](http://www.gotw.ca/publications/mill13。htm) –

0

什麼將優先:構建A或在堆中分配內存?

除非有記憶,否則沒有空間可以構建對象。內存分配總是優先;那麼代碼將繼續進行初始化。這適用於各種內存分配,而不僅僅是動態變化,因爲構造函數在開始初始化對象之前需要有一個有效的地址this

如果分配是第一個,如果有異常會如何解除分配?

編譯器發出處理「魔術」的特殊代碼。此代碼將爲所有基類以及成員(例如B)運行析構函數,這些成員在代碼輸入A的構造函數時已完全構建。

+0

謝謝,請您詳細介紹一下這個「特殊代碼」行爲嗎? – M90

+0

@ M90我已經做了:對已經完全構建的所有東西運行析構函數,然後將分配的內存返回到它來自的地方(在你的情況下,它來自堆,所以回到堆中)。 – dasblinkenlight