web-dev-qa-db-ja.com

コンストラクターでフィールドを初期化する-初期化子リストとコンストラクター本体

私は今しばらくの間c ++で働いていますが、私は違いがわからない

public : Thing(int _foo, int _bar): member1(_foo), member2(_bar){}

そして

public : Thing(int _foo, int _bar){
    member1 = _foo;
    member2 = _bar;
}

私はそれらが同じことをしていると感じていますが、これら2つの構文の間には実際的な違いがあります。これらのいずれかが他より安全であり、デフォルトのパラメータを異なる方法で処理します。

最初の例に完全に慣れていないので、もしそれを間違えた場合は謝罪します。

47
gardian06

member1member2が非POD(つまり、非-[〜#〜] p [〜#〜]lain [〜#〜] o [〜#〜] ld [〜#〜] d [〜#〜] ata)タイプ:

public : Thing(int _foo, int _bar){
    member1 = _foo;
    member2 = _bar;
}

と同等です

public : Thing(int _foo, int _bar) : member1(), member2(){
    member1 = _foo;
    member2 = _bar;
}

コンストラクター本体が実行を開始する前に初期化されるため、基本的に2倍の作業が行われます。つまり、これらのメンバーの型にデフォルトのコンストラクターがない場合、コードはnotコンパイルされます。

60
Luchian Grigore

最初の方法は推奨されるベストプラクティスです。これはより慣用的であり、既定のコンストラクターを持つ型(つまり、非プリミティブ型)のフィールドの再初期化を避けるためです。

コンストラクター本体内でメンバーを初期化するだけの場合、コンパイラーはデフォルトのメンバー初期化ステートメントを生成します(可能な場合)。そのため、最終的に二重に初期化されます。これは場合によっては大した問題ではないかもしれませんが、オブジェクトの構築に費用がかかる場合は、パフォーマンスのオーバーヘッドが深刻になる可能性があります。

更新

ただし、(n明示的に定義または生成された)デフォルトコンストラクターのないユーザー定義型は、この方法で初期化できないため、コンパイラエラーが生成されます。 constフィールドとreferenceフィールドについても同様です-これらは、メンバー初期化子リストで明示的にのみ初期化できます。

13
Péter Török

PéterTörök answerに追加する唯一のものは、初期化リストがオブジェクトのconstメンバーを初期化する唯一の方法であるということです。

class foo
{
public:

    foo(int value)
        : myConstValue(value)
    {};

    foo()
    {
        myConstValue = 0; // <=== Error! myConstValue is const (RValue), you can't assign!
    };

private:
    const int myConstValue;
}
7
PaperBirdMaster

サンプルコードでは、コンストラクターの初期化における最初のコードと、コンストラクター本体内の割り当てです。

コンストラクターの初期化リストは、パフォーマンスを改善するため、すべてのメンバーの初期化を行うための最良の方法です。

class A
{
string name;
public:
A(string myname):name(myname) {}
}

上記の場合、コンパイラは初期化を行うための一時オブジェクトを作成しません。ただし、次の場合:

A::A()
{
    name = myname;
}

個別の一時オブジェクトが作成され、この一時オブジェクトがstringの割り当て演算子に渡されて、nameに割り当てられます。その後、一時オブジェクトが破棄されますが、これは非常に効率的ではありません。

注:参照またはconstメンバーは、コンストラクターの初期化リストで初期化する必要があります。コンストラクターの本文で「割り当てる」ことはできません。

4
Sanish

他の答えとは別に、コンストラクタ変数の初期化はメンバー変数の初期化のみに言及したいと思います。

class Demo
{
    int a;
    int b;
public:
    Demo(int a,int b):a(a),b(b)
    {

    }

};

コンストラクタ内でaとbを初期化すると、自己割り当てになります。

2
user4016479

最初は初期化リストを使用した初期化で、2番目はデフォルトの構築と割り当てです。最初のものは、少なくとも2番目のものと同じくらい速く、2番目のものよりも好ましいです。

1
DumbCoder