18

初期化リストは常にコンストラクター コードの前に処理されますか?

つまり、次のコードは常に を出力し、構築されたクラスは(グローバル変数がの場合) の<unknown>値として「既知」を持ちますか?source_somethingtrue

class Foo {
  std::string source_;
public:
  Foo() : source_("<unknown>") {
    std::cout << source_ << std::endl;
    if(something){
      source_ = "known";
    }
  }
};
4

3 に答える 3

24

はい、次のようになります ( の同じC++11: 12.6.2 /10セクションC++14、):15.6.2 /13C++17


非委任コンストラクターでは、初期化は次の順序で行われます (太字):

  • まず、最も派生したクラス (1.8) のコンストラクターの場合のみ、仮想基底クラスは、基底クラスの有向非巡回グラフの深さ優先の左から右への走査に現れる順序で初期化されます。 to-right」は、派生クラス base-specifier-list 内の基本クラスの出現順序です。

  • 次に、直接基底クラスは、base-specifier-list に表示される宣言順に初期化されます (mem-initializer の順序に関係なく)。

  • 次に、非静的データ メンバーは、クラス定義で宣言された順序で初期化されます (これも mem-initializer の順序に関係なく)。

  • 最後に、コンストラクター本体の複合ステートメントが実行されます。


init-list を使用する主な理由は、コンパイラの最適化を支援することです。int非基本型 (つまり、 、 などではなくクラス オブジェクトfloat) の init-lists は、通常、その場で構築できます。

オブジェクトを作成してからコンストラクターで割り当てると、通常、一時オブジェクトの作成と破棄が行われ、非効率的になります。

init-lists はこれを避けることができます (もちろん、コンパイラーがそれに対応している場合ですが、ほとんどの場合はそうすべきです)。

次の完全なプログラムは 7 を出力しますが、これは特定のコンパイラ (CygWin g++) 用であるため、元の質問のサンプル以上の動作を保証するものではありません。

ただし、上記の最初の段落の引用によると、標準実際にそれを保証しています。

#include <iostream>
class Foo {
    int x;
    public:
        Foo(): x(7) {
            std::cout << x << std::endl;
        }
};
int main (void) {
    Foo foo;
    return 0;
}
于 2009-04-07T02:30:46.357 に答える
8

はい、C++ はコンストラクター コードを呼び出す前にすべてのメンバーを構築します。

于 2009-04-07T02:31:16.450 に答える