web-dev-qa-db-ja.com

ヒープ内のオブジェクトまたはスタック内の一時オブジェクトを作成するときに、構造体のPODが暗黙のコンストラクターによってゼロで初期化されるのはなぜですか?

標準およびthe C++の本によると、クラス型メンバーのデフォルトコンストラクターは、暗黙的に生成されたデフォルトコンストラクターによって呼び出されますが、組み込み型は初期化されません。ただし、このテストプログラムでは、ヒープ内のオブジェクトを割り当てるとき、または一時オブジェクトを使用するときに、予期しない結果が発生します。

#include<iostream>


struct Container
{
    int n;
};

int main()
{
    Container c;
    std::cout << "[STACK] Num: " << c.n << std::endl;

    Container *pc = new Container();
    std::cout << "[HEAP]  Num: " << pc->n << std::endl;
    delete pc;

    Container tc = Container();
    std::cout << "[TEMP]  Num: " << tc.n << std::endl;

}

私はこの出力を取得します:

[STACK] Num: -1079504552
[HEAP]  Num: 0
[TEMP]  Num: 0

これはコンパイラ固有の動作ですか?私はこれに頼るつもりはありませんが、特に3番目のケースで、なぜこれが発生するのか知りたいです。

31
Jacobo de Vera

予想される動作です。 「デフォルトの初期化」と「値の初期化」の2つの概念があります。初期化子について言及しない場合、オブジェクトは「デフォルトで初期化」されますが、言及すると、デフォルトのコンストラクターの()としても、オブジェクトは「値で初期化」されます。コンストラクターが定義されている場合、どちらの場合もデフォルトのコンストラクターを呼び出します。ただし、組み込み型の場合、「値の初期化」はメモリをゼロにしますが、「デフォルトの初期化」はそうではありません。

したがって、初期化するとき:

Type x;

デフォルトのコンストラクターが提供されている場合はそれを呼び出しますが、プリミティブ型は初期化されません。ただし、初期化子について言及する場合、たとえば.

Type x = {}; // only works for struct/class without constructor
Type x = Type();
Type x{}; // C++11 only

プリミティブ型(または構造体のプリミティブメンバー)はVALUEで初期化されます。

同様に:

struct X { int x; X(); };

コンストラクターを定義する場合

X::X() {}

xメンバーは初期化されませんが、コンストラクターを定義すると

X::X() : x() {}

vALUEで初期化されます。これはnewにも当てはまります。

new int;

初期化されていないメモリを提供するはずですが、

new int();

ゼロに初期化されたメモリを提供するはずです。残念ながら、構文は次のとおりです。

Type x();

文法のあいまいさのために許可されておらず、

Type x = Type();

は、デフォルトのコンストラクターを呼び出し、その後にcopy-constructorを呼び出す必要があります(指定されていて、インライン化できない場合)。

C++ 11では、新しい構文が導入されています。

Type x{};

これは両方の場合に使用できます。それでも古い標準に固執している場合は、Boost.ValueInitializedがあるので、テンプレート引数のインスタンスを適切に初期化できます。

より詳細な議論は、例えばで見つけることができます。 Boost.ValueInitializedドキュメント内

45
Jan Hudec

簡単な答えは次のとおりです。空の括弧は 値の初期化 を実行します。

あなたが言う時 Container *pc = new Container;代わりに、さまざまな動作が観察されます。

19
fredoverflow