2012-06-24 108 views
26

好的,成員變量can be used初始化初始化列表中的其他成員變量(小心初始化順序等)。關於成員函數呢?具體來說,這個片段是否符合C++標準?可以使用成員函數初始化初始化列表中的成員變量嗎?

struct foo{ 
    foo(const size_t N) : N_(N), arr_(fill_arr(N)) { 
    //arr_ = fill_arr(N); // or should I fall back to this one? 
    } 

    std::vector<double> fill_arr(const size_t N){ 
    std::vector<double> arr(N); 
    // fill in the vector somehow 
    return arr; 
    } 

    size_t N_; 
    std::vector<double> arr_; 
    // other stuff 
}; 
+0

問題是好的,但該代碼示例是有點人爲。什麼阻止你將'fill_arr'聲明爲'static',並且毫無疑問它的合法性? –

+0

這是線程安全的嗎?我的意思是,有一個向'fill_arr'定位的向量,如果這是'static',我可以通過某種互斥來保護它嗎? –

+2

'std :: vector arr'具有_automatic storage_,因此每次調用函數'fill_arr'時都會有一個實例。這很基本_C++ _... –

回答

30

是的,您在初始化列表中使用成員函數是有效的並符合標準。

數據成員按其聲明的順序進行初始化(這就是爲什麼它們應按照聲明的順序出現在初始化列表中的原因 - 您在示例中遵循的規則)。首先初始化N_,並且您可能已將此數據成員傳遞給fill_arr。在構造函數之前調用fill_arr,但因爲此函數不訪問未初始化的數據成員(它根本不訪問數據成員),所以它的調用被認爲是安全的。

下面是從C++標準的最新草案(N3242 = 11-0012)的一些相關節選:

§12.6.2.13:成員函數(包括虛擬成員函數, 10.3)可以被稱爲(...)然而,如果這些操作是在ctor-initializer中執行的(或者直接或間接從ctor初始化程序調用的函數 ),則在所有基類的mem初始化程序都有完成後, 操作的結果未定義。例如:

class A { public: A(int); }; 

class B : public A { 
    int j; 
public: 
    int f(); 
    B() : A(f()), // undefined: calls member function 
       // but base A not yet initialized 
    j(f()) { } // well-defined: bases are all initialized 
}; 

class C { 
public: 
    C(int); 
}; 

class D : public B, C { 
    int i; 
public: 
    D() : C(f()), // undefined: calls member function 
       // but base C not yet initialized 
    i(f()) { } // well-defined: bases are all initialized 
}; 

§12.7.1:對於具有一個非平凡的構造方法的對象,該 構造之前參照 任何非靜態成員或基類對象的開始執行的結果未定義的行爲。實施例

struct W { int j; }; 
struct X : public virtual W { }; 
struct Y { 
    int *p; 
    X x; 
    Y() : p(&x.j) { // undefined, x is not yet constructed 
    } 
}; 
3

初始化初始化列表中的對象時,該對象尚未完全構建。
如果這些函數試圖訪問尚未構造的對象部分,那麼這是一個未定義的行爲,否則它很好。
參見this answer

+0

這就是問題的真諦:成員函數的構造順序是什麼? –

+0

@ Zhenya看到這個:: http://stackoverflow.com/a/3899583/981787 – Eight

+0

糾正我,如果我錯了:你指的問題處理成員變量,而不是成員函數。你是否暗示會員職能遵循相同的規則?例如,如果我切換'arr_'和'fill_arr()'聲明的順序,gcc 4.4.3不會抱怨,但如果init-list中的順序與聲明順序不一致,它會發出警告。 –