2010-10-27 110 views
9

構造函數初始化列表中的執行順序是否可確定?我知道,在一個類成員順序是其中的成員將被初始化的順序,但如果我的情況是這樣的:構造函數初始化列表中的執行順序

class X() 
{ 
X_Implementation* impl_; 
}; 

and then providing that allocator is available: 

X::X():impl_(Allocate(sizeof(X_Implementation)))//HERE I'M ALLOCATING <--1 
,impl_(Construct<X_Implementation>(impl_))//AND HERE I'M CONSTRUCTING <--2 
{ 
} 

但爲了這是可靠的這個順序必須從左至右。是否通過std ::的偉大的書保證?如果不是,我總是可以將第二行移入身體。

+1

使用placement new構造到您之前分配的內存緩衝區中。 – 2010-10-27 22:11:36

+0

你不能多次初始化一個對象,所以這個問題是不合適的。除此之外,[構造函數初始化列表評估順序]的明顯重複(https://stackoverflow.com/questions/1242830/constructor-initialization-list-evaluation-order) – 2017-11-04 15:58:35

回答

28

根據ISO/IEC 14882:2003(E)第12.6.2:

初始化應按照下列順序進行:

  • 第一,並且僅針對如下所述的派生類最多的構造函數,虛擬基類將按照它們出現在基類的有向無環圖 的深度優先從左到右遍歷的順序進行初始化,其中「從左到右「我■派生的 類base-specifier-list中基類名稱的出現順序。
  • 然後,直接基類應按聲明順序進行初始化,因爲它們出現在基本說明符列表 (不管mem初始化程序的順序如何)中。
  • 然後,非靜態數據成員應按照它們在類定義 中聲明的順序進行初始化(不管mem-initializers的順序如何)。
  • 最後,執行構造函數的主體。

所以,按照這個順序,你會得到你的訂單。同樣根據該標準,順序被規定爲使得對象可以以相反的順序未初始化。

22

C++標準不保證初始化列表的順序(ISO C++標準12.6.2/5):

...非靜態數據成員應在他們在被宣佈 的順序 初始化類定義 (不管 mem初始化程序的順序如何)。

(有關詳細信息,請參閱Wyatt Anderson's answer。)

例子:

class Foo 
{ 
public: 
    Foo(); 
private: 
    A a; 
    B b; 
    C c; 
}; 

Foo::Foo() : b(), a(), c() 
{ 
    // a is initialized first, then b, then c - NOT b, a, then c! 
} 

但是,你不能初始化變量的兩倍 - 你不會編譯什麼。

class X //() what's with the pair of parentheses you have in your code snippet? 
{ 
public: 
    X(); 
private: 
    X_Implementation* impl_; 
}; 

X::X() : 
    impl_(Allocate(sizeof(X_Implementation))), 
    // It is not allowed to initialize a data member twice! 
    impl_(Construct<X_Implementation>(impl_)) 
{ 
} 

相反,只是把額外的工作變成構造:

X::X() : impl_(Allocate(sizeof(X_Implementation))) 
{ 
    impl_ = Construct<X_Implementation>(impl_); 
} 

可能有例外安全問題與上面的代碼,但不知道什麼Allocate()Construct()實際上做了我」米不能說。我可以告訴你,這是最好的配置和建設放在各自的類,如果你這樣做,使用資源獲取就是初始化(RAII)成語:

class XBase 
{ 
protected: 
    XBase() : impl_(Allocate(sizeof(X_Implementation))) 
    { 
    } 

    ~XBase() 
    { 
     if(impl_ != 0) { Deallocate(impl_); } // Or something like this 
    } 

    X_Implementation* impl_; 
}; 

class X : private XBase // XBase is an implementation detail 
{ 
public: 
    X() 
    { 
     impl_ = Construct<X_Implementation>(impl_); 
    } 

    ~X() 
    { 
     Destruct<X_Implementation>(impl_); // Or something like this 
    } 
}; 

這樣,如果Construct()拋出一個異常,你將不會泄漏內存,因爲將調用基類析構函數,這將釋放由impl_指向的內存。這很重要,因爲如果異常未被捕獲並且離開構造函數,則其匹配的析構函數將不會被稱爲。見了Bjarne Stroustrup的紙張上異常安全:http://www2.research.att.com/~bs/except.pdf

4

您的具體情況是基於不止一次初始化同一個成員的想法。這在C++中是非法的。你的代碼不會編譯。所以,你所問的問題並不存在。

成員初始化的順序是它們在類定義中聲明的順序。在無繼承上下文中,該上下文涵蓋與構造初始值設定項列表中的初始化順序相關的所有內容。