web-dev-qa-db-ja.com

この特定の場合、メンバー初期化子リストの使用とコンストラクターでの値の割り当てに違いはありますか?

内部的には、生成されたコードについて、本当に違いがあります:

MyClass::MyClass(): _capacity(15), _data(NULL), _len(0)
{
}

そして

MyClass::MyClass()
{
  _capacity=15;
  _data=NULL;
  _len=0
}

ありがとう...

88
Stef

これらの値がプリミティブ型であると仮定すると、いいえ、違いはありません。初期化リストは、オブジェクトをメンバーとして持つ場合にのみ違いをもたらします。これは、デフォルトの初期化の後に割り当てを使用する代わりに、初期化リストを使用してオブジェクトを最終値に初期化できるためです。これは実際には著しく高速です。

59
templatetypedef

定数メンバー、参照、および基本クラスを初期化するには初期化リストを使用する必要があります

コメントで述べたように、定数メンバー、参照を初期化し、基本クラスコンストラクターにパラメーターを渡す必要がある場合は、初期化リストを使用する必要があります。

struct aa
{
    int i;
    const int ci;       // constant member

    aa() : i(0) {} // will fail, constant member not initialized
};

struct aa
{
    int i;
    const int ci;

    aa() : i(0) { ci = 3;} // will fail, ci is constant
};

struct aa
{
    int i;
    const int ci;

    aa() : i(0), ci(3) {} // works
};

例(網羅的ではない)クラス/構造には参照が含まれます:

struct bb {};

struct aa
{
    bb& rb;
    aa(bb& b ) : rb(b) {}
};

// usage:

bb b;
aa a(b);

また、パラメーターを必要とする基本クラスを初期化する例(デフォルトコンストラクターなしなど):

struct bb {};

struct dd
{
    char c;
    dd(char x) : c(x) {}
};

struct aa : dd
{
    bb& rb;
    aa(bb& b ) : dd('a'), rb(b) {}
};
77
stefanB

はい。最初のケースでは、_capacity_dataおよび_lenを定数として宣言できます。

class MyClass
{
private:
    const int _capacity;
    const void *_data;
    const int _len;
// ...
};

実行時に値を計算する際にこれらのインスタンス変数のconst- nessを確認したい場合、これは重要です。例えば:

MyClass::MyClass() :
    _capacity(someMethod()),
    _data(someOtherMethod()),
    _len(yetAnotherMethod())
{
}

constインスタンス必須初期化子リストで初期化されるまたは基になる型は、パラメーターなしのパブリックコンストラクター(プリミティブ型が提供する)を提供する必要があります。

18
Richard Cook

このリンク http://www.cplusplus.com/forum/articles/17820/ は優れた説明を提供すると思います-特にC++を初めて使用する人にとっては。

Intialiserリストがより効率的である理由は、コンストラクター本体内では、初期化ではなく割り当てのみが行われるためです。したがって、非組み込み型を扱う場合、そのオブジェクトのデフォルトコンストラクターは、コンストラクターの本体が入力される前に既に呼び出されています。コンストラクター本体内では、そのオブジェクトに値を割り当てています。

実際には、これはデフォルトのコンストラクターの呼び出しと、それに続くコピー割り当て演算子の呼び出しです。初期化子リストを使用すると、コピーコンストラクターを直接呼び出すことができます。これは、かなり高速になる場合があります(初期化子リストはコンストラクターの本体の前にあることを思い出してください)

6
user929404

デフォルトのコンストラクターを使用できないクラス型のメンバーがある場合、初期化がクラスを構築する唯一の方法であると付け加えます。

5
Fred Larson

大きな違いは、割り当てによって親クラスのメンバーを初期化できることです。初期化子は、現在のクラススコープで宣言されたメンバーでのみ機能します。

3
Mark Ransom

関係するタイプに依存します。違いは

std::string a;
a = "hai";

そして

std::string a("hai");

2番目の形式は初期化リストです。つまり、型がコンストラクター引数を必要とする場合、またはコンストラクター引数を使用する方が効率的である場合に違いが生じます。

2
Puppy

実際の違いは、gccコンパイラーがマシンコードを生成してメモリを配置する方法に要約されます。説明:

  • (phase1)init body(initリストを含む)の前:コンパイラーはクラスに必要なメモリーを割り当てます。クラスはすでに生きています!
  • (phase2)init body:メモリが割り当てられているため、すべての割り当ては、すでに存在する/「初期化された」変数に対する操作を示します。

確かに、const型のメンバーを処理する他の方法があります。しかし、彼らの生活を楽にするために、gccコンパイラライターはいくつかのルールを設定することにしました

  1. const型のメンバーは、init本文の前に初期化する必要があります。
  2. フェーズ1の後、書き込み操作は非定数メンバーに対してのみ有効です。
1
lukmac

initialize基本クラスのインスタンスと非静的メンバー変数への唯一の方法があり、初期化リストを使用しています。

コンストラクタの初期化子リストでベースまたは非静的メンバー変数を指定しない場合、そのメンバーまたはベースはデフォルトで初期化されます(メンバー/ベースが非PODクラスタイプまたは非PODクラスの配列の場合)それ以外の場合は初期化されないままにします。

コンストラクター本体が入力されると、すべてのベースまたはメンバーは初期化されるか、初期化されないままになります(つまり、不定の値になります)。コンストラクター本体には、初期化方法に影響を与える機会はありません。

コンストラクター本体のメンバーに新しい値を割り当てることはできますが、constメンバーまたは割り当て不可にされたクラスタイプのメンバーに割り当てることはできず、参照を再バインドすることはできません。

組み込み型および一部のユーザー定義型の場合、コンストラクター本体での割り当ては、初期化子リストの同じ値での初期化とまったく同じ効果がある場合があります。

初期化子リストのメンバーまたはベースに名前を付けず、そのエンティティが参照であり、ユーザーが宣言したアクセス可能なデフォルトコンストラクターのないクラスタイプ、const修飾、PODタイプまたはPODクラスタイプの場合またはconst修飾メンバーを含むPODクラスタイプの配列(直接的または間接的に)の場合、プログラムの形式は正しくありません。

1
CB Bailey

初期化リストとコンストラクターの初期化ステートメントには違いがあります。以下のコードを考えてみましょう。

#include <initializer_list>
#include <iostream>
#include <algorithm>
#include <numeric>

class MyBase {
public:
    MyBase() {
        std::cout << __FUNCTION__ << std::endl;
    }
};

class MyClass : public MyBase {
public:
    MyClass::MyClass() : _capacity( 15 ), _data( NULL ), _len( 0 ) {
        std::cout << __FUNCTION__ << std::endl;
    }
private:
    int _capacity;
    int* _data;
    int _len;
};

class MyClass2 : public MyBase {
public:
    MyClass2::MyClass2() {
        std::cout << __FUNCTION__ << std::endl;
        _capacity = 15;
        _data = NULL;
        _len = 0;
    }
private:
    int _capacity;
    int* _data;
    int _len;
};

int main() {
    MyClass c;
    MyClass2 d;

    return 0;
}

MyClassを使用すると、コンストラクターの最初のステートメントが実行される前にすべてのメンバーが初期化されます。

ただし、MyClass2を使用すると、コンストラクターの最初のステートメントが実行されたときにすべてのメンバーが初期化されません。

後の場合、特定のメンバーが初期化される前に誰かがコンストラクターにコードを追加すると、回帰の問題が発生する可能性があります。

0
user928143

初期化リストを作成する場合、すべてを1つのステップで実行します。初期化リストを作成しない場合は、2つのステップを実行します。1つは宣言用、もう1つは値の割り当て用です。

0

ここに、他の人がそれを参照しているのを見なかった点があります:

class temp{
public:
   temp(int var);
};

Tempクラスにはデフォルトのctorはありません。次のように別のクラスで使用する場合:

class mainClass{
public:
 mainClass(){}
private:
  int a;
  temp obj;
};

コードはコンパイルされません。コンパイラはobjを初期化する方法を知りません。int値を受け取る明示的なctorだけがあるため、次のようにctorを変更する必要があります。

mainClass(int sth):obj(sth){}

したがって、constとreferenceだけではありません!

0
hosh0425