2012-06-24 157 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中的顺序与声明顺序不一致,它会发出警告。 –