6

GCC 4.6.1 で、デフォルトのコンストラクターを持つ独自の型のインスタンスを宣言し、その型のオブジェクトをインスタンス化して中かっこ ( Foo my_foo{}; など) で初期化すると、そのクラスの POD メンバー他のコンストラクターが宣言されていない場合にのみゼロ初期化します。デフォルトのもの以外に他のコンストラクターがない場合、期待どおりにゼロ初期化されます。

しかし、GCC 4.7.3 では、どちらの方法でもゼロ初期化が行われます。これは、私が期待した動作です。

ここの違いは何ですか?これはコンパイラのバグですか? これらの GCC バージョンは両方とも、C++11 標準のデフォルトのコンストラクターをサポートしています。

古い GCC バージョンに固執する必要はありませんが、ここで何が起こっているのかを理解したいと思います。

注:メインのctor、op =をデフォルトにしています。可変個引数関数で型を使用できるようにするためだけに ctor をコピーします (clang は、クラスを POD として分類するためにこれを要求しますが、gcc では、ユーザー定義のメイン ctor であっても、可変個引数関数で型を使用することを回避できます。私はなぜ。)

以下は、(両方の GCC バージョンでコンパイルされたバイナリからの) 下部にいくつかの出力を含む、説明するためのサンプル プログラムです。

#include <cstdio>

// pod and pod_wctor are identical except that pod_wctor defines another ctor

struct pod {
    pod( void ) = default;
    pod( const pod& other ) = default;
    pod& operator=( const pod& other ) = default;

    int x,y,z;
};

struct pod_wctor {
    pod_wctor( void ) = default;
    pod_wctor( const int setx, const int sety, const int setz ) : x(setx), y(sety), z(setz) { }
    pod_wctor( const pod_wctor& other ) = default;
    pod_wctor& operator=( const pod_wctor& other ) = default;

    int x,y,z;
};

int main ( void ) {

    printf("the following shuold be uninitialized:\n");

    pod pee;
    printf( "    %i,%i,%i\n", pee.x, pee.y, pee.z);

    pod_wctor podtor;
    printf( "    %i,%i,%i\n", podtor.x, podtor.y, podtor.z);

    printf("the following shuold be initialized to 0,0,0:\n");

    pod peenit{};
    printf( "    %i,%i,%i\n", peenit.x, peenit.y, peenit.z );

    pod_wctor podtornit{};
    printf( "    %i,%i,%i\n", podtornit.x, podtornit.y, podtornit.z );

    return 0;

}

// compiled with: g++ m.cpp -std=gnu++0x
// g++ (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1 (i386)
/****************** output *******************
the following shuold be uninitialized:
    10381592,134513249,134520820
    134513969,134513504,0
the following shuold be initialized to 0,0,0:
    0,0,0
    7367877,134513945,8724468
*********************************************/

// compiled with: g++ m.cpp -std=gnu++0x
// gcc version 4.7.3 (Ubuntu/Linaro 4.7.3-2ubuntu4) (i386)
/****************** output *******************
the following shuold be uninitialized:
    -1218358300,-1217268232,134520832
    134514450,1,-1079827548
the following shuold be initialized to 0,0,0:
    0,0,0
    0,0,0
*********************************************/
4

1 に答える 1

2

クラスにコンストラクターを追加するpod_wctor( const int setx, const int sety, const int setz ) : x(setx), y(sety), z(setz) { }と、集約としてのステータスが失われます: [dcl.init.aggregate]/1

集約は、ユーザー提供のコンストラクターを持たない配列またはクラス (第 9 節) です。

自明なクラスは非自明なデフォルトctors のみを必要とするため、これはまだ PODです: [class]/6

自明なクラスは、デフォルトのコンストラクター (12.1) を持ち、非自明なデフォルト コンストラクターを持たず、自明にコピー可能なクラスです。


ここで興味深い点は、集計の場合、リストの初期化pod peenit{};が集計の初期化を実行することです。

型のオブジェクトまたは参照のリスト初期化は、T次のように定義されます。

  • が集合体の場合T、集合体の初期化が実行されます (8.5.1)。[...]
  • それ以外の場合、初期化子リストに要素がなくT、既定のコンストラクターを持つクラス型である場合、オブジェクトは値で初期化されます。

(注:これは改訂された順序です。知る限り、標準自体では、これら2つのポイントの順序が逆になっています。これは、すべての集約にデフォルトのctor(暗黙的に宣言および定義されたもの)があるため、これは欠陥に違いありません。)

集計の初期化は、intメンバーの値の初期化につながります: [dcl.init.aggr]/7

集約内のメンバーよりもリスト内の初期化句の数が少ない場合、明示的に初期化されていない各メンバーは、空の初期化子リストから初期化されます。

および [dcl.init.list]/3 「それ以外の場合、イニシャライザ リストに要素がない場合、オブジェクトは値で初期化されます」


ただし、非集計pod_wctorの場合、リストの初期化pod_wctor podtornit{}はデフォルトの ctor を呼び出す値の初期化を直接実行します。[class.ctor]/6 は次を指定します。

暗黙的に定義されたデフォルト コンストラクターは、ctor -initializer (12.6.2) と空の Compound -statementを使用せずに、そのクラスのユーザー作成のデフォルト コンストラクターによって実行されるクラスの初期化のセットを実行します。

[class.base.init]/8 では、次のことがわかります。

非委任コンストラクターで、特定の非静的データ メンバーまたは基底クラスがmem-initializer-idによって指定されていない場合 (コンストラクターにctor-initializerがないためにmem-initializer-listがない場合を含む)エンティティが抽象クラス (10.4) の仮想基底クラスではない場合、

  • [...]
  • それ以外の場合、エンティティはデフォルトで初期化されます (8.5)。

既定の ctor自体は、メンバーの既定の初期化のみを行うため、メンバーのゼロ化を保証しません。


デフォルトと値の初期化の違い: [dcl.init]

[7]タイプのオブジェクトをデフォルトで初期化Tするとは、次のことを意味します。

  • T(おそらくcv修飾された) クラス型である場合、 のデフォルトのコンストラクターTが呼び出されます [...]
  • [...]
  • それ以外の場合、初期化は実行されません。

[...]

[8]型のオブジェクトを値で初期化Tするとは、次のことを意味します。

  • デフォルトのコンストラクターがないか、ユーザー提供または削除されたデフォルトのコンストラクターをT持つ (おそらくcv修飾された) クラス型である場合、オブジェクトはデフォルトで初期化されます。
  • ユーザー提供または削除されたデフォルト コンストラクターを持たないT(おそらくcv修飾された) 非共用体クラス型の場合、オブジェクトはゼロで初期化Tされ、自明でないデフォルト コンストラクターがある場合はデフォルトで初期化されます。
  • [...]
  • それ以外の場合、オブジェクトはゼロで初期化されます。

(これが私を混乱させたことを認め、答えを修正しなければなりませんでした。)

pod_wctorユーザー提供ではないデフォルトコンストラクターがあります。したがって、 list-initializationの場合、 value-initializationpod_wctor podtornit{}の 2 番目の箇条書きが適用されます。オブジェクト自体はzero-initializedであり、そのメンバーのゼロ初期化につながります。そうして初めて、デフォルトで初期化され、デフォルトのctorが呼び出されます。後者は何もしませんが、前者はメンバーがゼロになることを保証します。podtornit

于 2013-09-19T18:36:10.510 に答える