web-dev-qa-db-ja.com

C ++に暗黙的なデフォルトコンストラクタがありますか?

私が現在読んでいる本( C++ Without Fear )では、クラスのデフォルトコンストラクターを宣言しない場合、コンパイラーが1つを提供します。データメンバー」。私はこれを実験しましたが、ゼロアウト動作は見られません。また、Googleでこれについて言及しているものは見つかりません。これは単なるエラーですか、それとも特定のコンパイラの癖ですか?

62
Skilldrick

コンストラクターを定義しない場合、コンパイラーはデフォルトのコンストラクターを定義します。

これの実装

デフォルトのコンストラクタは次のとおりです。

  • デフォルトは基本クラスを構築します(基本クラスにデフォルトコンストラクターがない場合、これはコンパイルの失敗です)
  • デフォルトでは、宣言順に各メンバー変数を構築します。 (メンバーにデフォルトのコンストラクターがない場合、これはコンパイルの失敗です)。

注意:
PODデータ(int、float、pointerなど)には明示的なコンストラクターはありませんが、デフォルトのアクションは何もしないことです(C++哲学の見地から。明示的に要求してください)。

デストラクタ/コピーコンストラクタ/代入演算子が定義されていない場合、コンパイラはそれらのいずれかをビルドします(したがって、クラスには常にデストラクタ/コピーコンストラクタ/代入演算子があります(チートして明示的に宣言するが定義しない限り)。
デフォルトの実装は次のとおりです。

デストラクタ:

  • ユーザー定義のデストラクタが定義されている場合、提供されたコードを実行します。
  • 宣言の逆順で各メンバーのデストラクタを呼び出します
  • 基本クラスのデストラクタを呼び出します。

コンストラクターのコピー:

  • BaseクラスのCopy Constructorを呼び出します。
  • 宣言順に各メンバー変数のコピーコンストラクターを呼び出します。

割り当て演算子:

  • 基本クラス割り当て演算子を呼び出す
  • 宣言の順に各メンバー変数の代入演算子を呼び出します。
  • これへの参照を返します。

注POD DataのCopy Construction/Assignment演算子は、データをコピーしているだけです(そのため、RAWポインターに関連する浅いコピーの問題)。

63
Martin York

constructor whatsoeverを指定した場合、デフォルトのコンストラクターはコンパイラーによってのみ作成されることに注意してください。つまり、引数を取るコンストラクターを1つだけ提供する場合、コンパイラーはnotを使用してデフォルトの引数なしのコンストラクターを作成します。

あなたの本が述べているゼロ化動作は、おそらく特定のコンパイラに固有のものです。私は常にそれが変化する可能性があり、データメンバを明示的に初期化する必要があると考えてきました。

37
Bill the Lizard
  • コンパイラーはデフォルトのコンストラクターを自動的に生成しますか?
  • 暗黙的に生成されたデフォルトコンストラクターはゼロの初期化を実行しますか?

2003標準の言語を合法的に解析する場合、答えはyes、およびno。ただし、これはストーリー全体ではありませんユーザー定義のデフォルトコンストラクタとは異なり、暗黙的に定義されたデフォルトコンストラクタ常に使用されるわけではありませんオブジェクトをゼロから作成する場合-他の2つのシナリオがあります:no constructionおよびmember -wise value-initialization

「構築なし」の場合は、機能的にはtrivialデフォルトコンストラクターの呼び出しと変わらないため、実際には単なる技術です。もう1つのケースはもっと興味深いです。メンバーごとの値の初期化は、「()」を使用して呼び出されます[あたかも引数のないコンストラクタを明示的に呼び出すかのように]および技術的に参照されるものをバイパスしますasthedefault constructor代わりに、各データメンバーで値の初期化を再帰的に実行し、プリミティブデータ型の場合、これは最終的にzero-initializationに解決されます。

したがって、実際には、コンパイラーは、2つの異なる暗黙的に定義されたデフォルトのコンストラクターを提供します。 1つはdoesでプリミティブメンバーデータのゼロ初期化を実行し、もう1つは実行しません。以下に、各タイプのコンストラクターを呼び出す方法の例を示します。

    MyClass a; // default-construction or no construction
    MyClass b = MyClass(); // member-wise value-initialization

そして

    new MyClass; // default-construction or no construction
    new MyClass(); // member-wise value-initialization

注:user-declaredデフォルトコンストラクターdoesが存在する場合、メンバーごとの値の初期化のみそれを呼び出して停止します。


これについては、規格が言っていることのやや詳細な内訳があります...

  • コンストラクターを宣言しない場合、コンパイラーはデフォルトのコンストラクターを暗黙的に作成します[12.1-5]

  • デフォルトのコンストラクタはプリミティブ型を初期化しません[12.1-7]

    MyClass() {} // implicitly defined constructor
    
  • 「()」でオブジェクトを初期化する場合、これはデフォルトのコンストラクターを直接呼び出しません。代わりに、value-initialization[8.5-7]と呼ばれる長い一連のルールを引き起こします

  • 値の初期化の最終的な効果は、暗黙的に宣言されたデフォルトコンストラクターが呼び出されないことです。代わりに、再帰的なメンバーごとの値の初期化が呼び出され、最終的にすべてのプリミティブメンバーがゼロで初期化され、ユーザーを持つメンバーでデフォルトコンストラクターが呼び出されます-宣言されたコンストラクタ[8.5-5]

  • 値の初期化はプリミティブ型にも適用されます。これらはゼロで初期化されます。 [8.5-5]

    a = int(); // equivalent to int a=0;
    

これはすべて、ほとんどの目的にとって本当に意味がありません。クラスの作成者は、通常、暗黙的な初期化シーケンス中にデータメンバーがゼロになると想定することはできません。したがって、自己管理クラスは、初期化を必要とするプリミティブデータメンバーがある場合、独自のコンストラクターを定義する必要があります。

それで、これはいつ重要ですか?

  • 汎用コードが不明な型の初期化を強制したい状況があるかもしれません。値の初期化は、これを行う方法を提供します。ユーザーがコンストラクターを指定した場合、暗黙的なゼロ初期化は行われないことに注意してください。

  • デフォルトでは、std :: vectorに含まれるデータは値で初期化されます。これにより、メモリデバッガが初期化されていないメモリバッファに関連する論理エラーを識別できなくなります。

    vector::resize( size_type sz, T c=T() ); // default c is "value-initialized"
    
  • プリミティブ型の配列全体または「plain-old-data」(POD)型構造は、値の初期化構文を使用してゼロで初期化できます。

    new int[100]();
    

この投稿 には、標準のバージョン間のバリエーションに関する詳細が記載されています。また、主要なコンパイラで標準が異なる方法で適用される場合も記載されています。

34
nobar

C++はデフォルトのコンストラクターを生成しますが、独自のコンストラクターを提供しない場合のみです。この規格では、データメンバーのゼロ化については何も述べていません。デフォルトでは、オブジェクトを最初に構築したとき、それらは未定義です。

ほとんどのC++プリミティブ型には、ゼロに初期化するデフォルトの「コンストラクター」(int()、bool()、double()、long()、etc。)が、コンパイラはオブジェクトメンバの場合のようにPODメンバを初期化するためにそれらを呼び出しません。

STLdoesはこれらのコンストラクターを使用して、プリミティブ型を保持するコンテナーのコンテンツをデフォルトで構築することに注意してください。 STLコンテナの内容が初期化される方法の詳細については、 この質問 をご覧ください。

20
Todd Gamblin

クラス用に作成されたデフォルトコンストラクターは組み込み型を初期化しませんが、すべてのユーザー定義メンバーでデフォルトコンストラクターを呼び出します。

class Foo
{
public:
     int x;
     Foo() : x(1) {}
};

class Bar
{
public:
     int y;
     Foo f;
     Foo *fp;
};

int main()
{

    Bar b1; 
    ASSERT(b1.f.x == 1); 
    // We know nothing about what b1.y is set to, or what b1.fp is set to.

    // The class members' initialization parallels normal stack initialization.
    int y;  
    Foo f; 
    Foo *fp; 
    ASSERT(f.x == 1);
    // We know nothing about what y is set to, or what fp is set to.

}
11
Eclipse

ユーザーが作成したものが存在しない場合、コンパイラーはデフォルトのコンストラクターとデストラクターを生成します。これらは、データメンバーの状態を変更しません。

C++(およびC)では、割り当てられたデータの内容は保証されません。デバッグ構成では、一部のプラットフォームはこれを既知の値(0xFEFEFEFEなど)に設定してバグの特定を支援しますが、これに依存するべきではありません。

5
Andrew Grant

C++はnotがメモリのゼロ化を保証します。 JavaおよびC#は(話し方で)行います。

一部のコンパイラは、依存する可能性がありますが、依存しません。

4
Jason Cohen

ゼロ消去は、グローバルに対してのみ発生します。したがって、オブジェクトがグローバルスコープで宣言されている場合、そのメンバーはゼロになります。

class Blah
{
public:
    int x;
    int y;
};

Blah global;

int main(int argc, char **argv) {
    Blah local;
    cout<<global.x<<endl;  // will be 0
    cout<<local.x<<endl;   // will be random
}
4
codelogic

C++ 11では、コンパイラーによって生成されたデフォルトコンストラクターは、次の場合にdeletedとマークされます。

  • クラスには参照フィールドがあります
  • または、ユーザー定義のデフォルトコンストラクターのないconstフィールド
  • または、デフォルトの初期化子がなく、デフォルトのコンストラクターが削除されたフィールド

http://en.cppreference.com/w/cpp/language/default_constructor

2
Nice Books

C++はデフォルトのコンストラクターを生成します。必要に応じて(コンパイル時に決定)、デフォルトのコピーコンストラクターとデフォルトの割り当てコンストラクターも生成します。ただし、メモリのゼロ化の保証については聞いていません。

1
Jason Punyon

コンパイラーは、デフォルトのコンストラクターを必要としない限り、デフォルトでデフォルトのコンストラクターを生成しません。したがって、基本的に、コンストラクタはnon-trivial constructorでなければなりません。

コンストラクターが重要なコンストラクターであるために、次の条件はどれでも十分です。

1)クラスには仮想メンバー関数があります。 2)クラスメンバーのサブオブジェクトまたは基本クラスには、重要なコンストラクターがあります。 3)クラスには仮想継承階層があります。

1
rahul