web-dev-qa-db-ja.com

メンバー関数を使用して、初期化リストのメンバー変数を初期化できますか?

OK、メンバー変数 使用可能 初期化リストの他のメンバー変数を初期化します(初期化の順序などに注意してください)。メンバー関数はどうですか?具体的には、このスニペットは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
};
34
ev-br

はい、初期化リストでのメンバー関数の使用は有効であり、標準に準拠しています。

データメンバーは宣言の順序で初期化されます(それが、宣言の順序で初期化リストに表示されるのはそのためです-例で使用したルール)。 N_が最初に初期化され、このデータメンバーをfill_arrに渡すことができます。 fill_arrはコンストラクタの前に呼び出されますが、この関数は初期化されていないデータメンバーにアクセスしないため(データメンバーにはまったくアクセスしません)、その呼び出しは安全と見なされます。

次に、C++標準の最新のドラフト(N3242 = 11-0012)からの関連する例外をいくつか示します。

§12.6.2.13:構築中のオブジェクトに対してメンバー関数(仮想メンバー関数を含む10.3)を呼び出すことができます。(...)ただし、これらの操作がctor-initializer(または直接または間接的に呼び出される関数)で実行される場合ctor-initializerから)、基本クラスのすべてのmem-initializerが完了するまで、操作の結果は未定義です。例:

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
   }
};
37
Bojan Komazec

初期化リストのオブジェクトを初期化している間、オブジェクトはまだ完全に構築されていません。
それらの関数がまだ構築されていないオブジェクトの部分にアクセスしようとする場合、それは未定義の動作です。
参照 この答え

6
Eight