94

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

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

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

ありがとう...

4

12 に答える 12

77

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

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

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) {}
};
于 2011-01-03T23:12:24.823 に答える
63

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

于 2011-01-03T23:09:03.150 に答える
18

はい。_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インスタンスは初期化子リストで初期化する必要があります。そうでない場合、基になる型はパブリックパラメーターなしのコンストラクター(プリミティブ型が行う)を提供する必要があります。

于 2011-01-03T23:09:09.500 に答える
7

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

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

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

于 2013-03-16T09:08:51.193 に答える
5

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

于 2011-01-03T23:11:07.700 に答える
3

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

于 2011-01-03T23:10:17.170 に答える
2

関係するタイプによって異なります。違いは

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

std::string a("hai");

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

于 2011-01-03T23:10:57.047 に答える
1

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

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

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

  1. const型のメンバーは、init本体の前に初期化する必要があります。
  2. フェーズ1の後、書き込み操作は非定数メンバーに対してのみ有効です。
于 2011-01-04T00:31:40.230 に答える
1

基本クラスインスタンスと非静的メンバー変数を初期化する唯一の方法があり、それは初期化子リストを使用することです。

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

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

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

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

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

于 2011-01-04T00:34:58.950 に答える
0

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

于 2012-01-13T08:34:51.947 に答える
0

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

#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を使用する場合、コンストラクターの最初のステートメントが実行されたときに、すべてのメンバーが初期化されるわけではありません。

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

于 2016-03-18T10:28:53.783 に答える
0

これが私が他の人がそれを参照しているのを見なかった点です:

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

一時クラスにはデフォルトのコンストラクターがありません。次のように別のクラスで使用する場合:

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

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

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

だから、それはconstとreferencesだけではありません!

于 2019-08-26T14:43:39.277 に答える