2013-04-16 25 views
2

以下代碼來自「異常處理」中。作者試圖告訴我們,通過將所有東西都作爲對象,我們可以防止資源泄漏。 我的問題: 爲什麼'cat'和'dog'的構造函數早於'useresources'的構造函數調用?哪個構造函數被調用第一個

//: C07:Wrapped.cpp 
// Safe, atomic pointers 
#include <fstream> 
#include <cstdlib> 
using namespace std; 
ofstream out("wrapped.out"); 
// Simplified. Yours may have other arguments. 
template<class T, int sz = 1> class PWrap { 
    T* ptr; 
public: 
    class RangeError {}; // Exception class 
    PWrap() { 
     ptr = new T[sz]; 
     out << "PWrap constructor" << endl; 
    } 
    ~PWrap() { 
     delete []ptr; 
     out << "PWrap destructor" << endl; 
    } 
    T& operator[](int i) throw(RangeError) { 
     if(i >= 0 && i < sz) return ptr[i]; 
     throw RangeError(); 
    } 
}; 
class Cat { 
public: 
    Cat() { out << "Cat()" << endl; } 
    ~Cat() { out << "~Cat()" << endl; } 
    void g() {} 
}; 
class Dog { 
public: 
    void* operator new[](size_t sz) { 
     out << "allocating an Dog" << endl; 
     throw int(47); 
    } 
    void operator delete[](void* p) { 
     out << "deallocating an Dog" << endl; 
     ::delete p; 
    } 
}; 
class UseResources { 
    PWrap<Cat, 3> Bonk; 
    PWrap<Dog> Og; 
public: 
    UseResources() : Bonk(), Og() { 
     out << "UseResources()" << endl; 
    } 
    ~UseResources() { 
     out << "~UseResources()" << endl; 
    } 
    void f() { Bonk[1].g(); } 
}; 
int main() { 
    try { 
     UseResources ur; 
    } catch(int) { 
     out << "inside handler" << endl; 
    } catch(...) { 
    out << "inside catch(...)" << endl; 
    } 
} ///:~ 
+3

他們不是。但是它們在'out <<「UseResources()」<< endl;'之前被調用。當你輸入構造函數的主體時,所有的成員對象都會調用它的構造函數。 – john

回答

3

爲什麼「貓」和「狗」的構造函數早不同於「useresources」的構造?

他們早於UseResources構造的稱爲輸入。

UseResources有兩個數據成員,它們是PWrap<>類模板的實例。的PWrap<T>的構造實例化一個數T類型的對象:

ptr = new T[sz]; 

因此導致呼叫的T構造的相應的號碼(或CatDog,你的情況)。

由於您的PWrap對象是數據成員UseResources,因此在構造函數的主體被輸入之前,它們的構造函數會被執行。這是C++中對象構造的工作原理。

這樣做的理由是爲了確保已進入了一個構造函數體的時候,所有的子對象(包括基地的子對象和成員子對象 - 如BonkOg)的構造已經完成。

這樣一來,構造函數可以依賴於使用有效的子對象,當它被執行時,它的類不變量已經建立。

這是C++ 11標準第12.6.2/10如何描述過程:

在非委託構造函數,以下列順序進行初始化:

- 第一,並且僅對於大多數派生類(1.8)的構造函數,虛擬基類在 中初始化它們出現在基類的有向無環圖的深度優先從左到右的遍歷中的順序,其中「left 「從右到左」是派生類base-specifier-list中基類的出現順序。

- 然後,直接基類以聲明順序初始化,因爲它們出現在基本說明符列表 (不管mem初始化程序的順序如何)中。

- 然後,非靜態數據成員在他們的類定義 被宣佈爲(再次不管MEM-初始化的順序)的順序進行初始化。

- 最後,執行構造函數體的複合語句

[注意:聲明順序要求確保基本和成員子對象以 銷燬的初始化順序相反。 - 注完]

0

代碼段:

UseResources() : Bonk(), Og() { 
     out << "UseResources()" << endl; 
    } 

其實你在呼喚UseResources構造構建邦克和噩成員之前只是outstreaming你的日誌後

1

構造函數的順序呼叫是:

  1. 基類。
  2. 成員,爲了它們出現在頭文件中
  3. 類構造函數。

UseResources類在調用構造函數的主體之前是「構造的」,關於它的大小和成員變量有正確的地址。但是,它們尚未完全構建。

構造函數的主體可以假定其所有成員都已經完全構造(調用其構造函數),因此必須按此順序調用它們。

因此,Bonk和Og按照UseResources之前的順序調用它們的構造函數。

相關問題