Search code examples
c++membermember-initializationctor-initializer

Can member functions be used to initialize data members in the member initializer list?


OK, member variables can be used to initialize other member variables in an initialization list (with care taken about the initialization order etc). What about member functions? To be specific, is this snippet legal according to the C++ standard?

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
};

Solution

  • Yes, your use of member function in initialization list is valid and complies with the standard.

    Data members are initialized in the order of their declaration (and that's the reason why they should appear in the initialization list in the order of their declaration - the rule that you followed in your example). N_ is initialized first and you could have passed this data member to fill_arr. fill_arr is called before constructor but because this function does not access uninitialized data members (it does not access data members at all) its call is considered safe.

    Here are some relevant excepts from the latest draft (N3242=11-0012) of the C++ standard:

    § 12.6.2.13: Member functions (including virtual member functions, 10.3) can be called for an object under construction.(...) However, if these operations are performed in a ctor-initializer (or in a function called directly or indirectly from a ctor-initializer) before all the mem-initializers for base classes have completed, the result of the operation is undefined. Example:

    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: For an object with a non-trivial constructor, referring to any non-static member or base class of the object before the constructor begins execution results in undefined behavior. Example

    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
       }
    };