36

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

2 に答える 2

39

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

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

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

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

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
   }
};
于 2012-06-24T02:51:57.770 に答える
6

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

于 2012-06-24T00:59:51.483 に答える