1. ホーム
  2. c++

[解決済み] デフォルト、値、ゼロ初期化ガチャ

2023-02-15 13:25:52

質問

値やデフォルト、ゼロ初期化について非常に混乱しています。 特に、異なる標準のためにそれらが起動するとき C++03 C++11 (そして C++14 ).

私は本当に良い答えを引用し、拡張しようとしています。 値-/デフォルト-/ゼロ- 初期値 C++98 C++03 というのは、もし誰かが必要なギャップを埋めるのを手伝ってくれて、いつ何が起こるかについての良い概要を持つことができれば、多くのユーザーを助けることができるからです。

一言で言えば、例による完全な洞察です。

new 演算子によって返されるメモリは、初期化されることもあれば、初期化されないこともあります。これは、新規作成される型が POD (プレーンオールドデータ) であるか、または POD メンバを含むクラスでコンパイラが生成したデフォルト コンストラクタを使用しているかによって異なります。

  • C++1998 には、2 種類の初期化があります。 ゼロ デフォルト初期化
  • C++2003 では、3 番目のタイプの初期化です。 値による初期化 が追加されました。
  • c++2011/c++2014 のみ リスト初期化 のルールが追加され 値/デフォルト/ゼロの初期化 が少し変更されました。

想定してください。

struct A { int m; };                     
struct B { ~B(); int m; };               
struct C { C() : m(){}; ~C(); int m; };  
struct D { D(){}; int m; };             
struct E { E() = default; int m;}; /** only possible in c++11/14 */  
struct F {F(); int m;};  F::F() = default; /** only possible in c++11/14 */

C++98コンパイラでは、以下のようになります。 :

  • new A - 不定値( A はPOD)
  • new A() - ゼロイニシャライズ
  • new B - デフォルトコンストラクト ( B::m は初期化されません。 B は非POD)
  • new B() - デフォルトの構成 ( B::m は初期化されない)
  • new C - デフォルトコンストラクト ( C::m はゼロ初期化されます。 C は非POD)
  • new C() - デフォルトの構成 ( C::m はゼロ初期化)
  • new D - デフォルトコンストラクト ( D::m は初期化されません。 D は非POD)
  • new D() - デフォルトの構成? ( D::m は初期化されません)

C++03に準拠したコンパイラでは、このように動作するはずです。

  • new A - 不定値( A はPOD)
  • new A() - 値初期化 A というのは、PODなのでゼロ初期化です。
  • new B - デフォルトの初期化 (葉 B::m は未初期化です。 B は非POD)
  • new B() - 値による初期化 B これは、デフォルトの Ctor がユーザー定義ではなく、コンパイラによって生成されるため、全てのフィールドをゼロ初期化します。
  • new C - デフォルトで初期化する C で、これはデフォルトの ctor を呼び出します。( C::m はゼロ初期化されます。 C は非POD)
  • new C() - 値による初期化 C で、これはデフォルトのコー タを呼び出します。 ( C::m はゼロ初期化)
  • new D - デフォルトコンストラクト ( D::m は初期化されません。 D は非POD)
  • new D() - 値を初期化する D? で、これはデフォルトのコー タを呼び出します ( D::m は初期化されない)

斜体の値と?は不確定要素なので、修正にご協力ください :-)

C++11 準拠のコンパイラでは、このように動作するはずです。

??? (ここから始めると、どうせうまくいかないので、助けてください)

C++14 準拠のコンパイラでは、このように動作するはずです。 ??? (ここから始めると、どうせうまくいかないので、助けてください) (回答に基づいてドラフト)

  • new A - デフォルトの初期化 A コンパイラ gen. ctor, (leavs A::m 未初期化) ( A はPOD)

  • new A() - 値による初期化 A にある点なので、ゼロ初期化です。 [dcl.init]/8

  • new B - デフォルトの初期化 B コンパイラ gen.ctor, (leavs) B::m 未初期化) ( B は非POD)

  • new B() - 値による初期化 B これは、そのデフォルトのCTORがユーザー定義ではなく、コンパイラが生成したものであるため、全てのフィールドをゼロ初期化します。

  • new C - デフォルトの初期化 C で、これはデフォルトの ctor を呼び出します。( C::m はゼロ初期化されます。 C は非POD)

  • new C() - 値による初期化 C で、これはデフォルトのコー タを呼び出します。( C::m はゼロ初期化)

  • new D - デフォルトの初期化 D ( D::m は初期化されていません。 D は非POD)

  • new D() - 値による初期化 D であり、デフォルトの Ctor ( D::m は初期化されない)

  • new E - デフォルトの初期化 E であり、コンパイル元CTORを呼び出しています。( E::m は初期化されていない、Eは非POD)

  • new E() - 値による初期化 E を初期化し、ゼロ初期化 E で2点なので [dcl.init]/8 )

  • new F - デフォルトの初期化 F であり、コンパイル元CTORを呼び出しています。( F::m は初期化されていません。 F は非POD)

  • new F() - 値による初期化 F であり、これは デフォルト初期化 F での1.ポイントから [dcl.init]/8 ( F ctor関数は、ユーザが宣言し、最初の宣言で明示的にデフォルトまたは削除されない場合、ユーザが提供するものです。 リンク )

どのように解決するのですか?

C++14 では、以下の方法で作成されたオブジェクトの初期化が規定されています。 new で作成されたオブジェクトの初期化を指定します(C++11 では [expr.new]/15 で、当時は注記ではなく規範的なテキストでした)。

A 新しい式 型のオブジェクトを作成する T はそのオブジェクトを次のように初期化します。 オブジェクトを次のように初期化します。

  • もし 新イニシャライザー が省略された場合、そのオブジェクトは default-initializedとなります。 (8.5). [ 注意してください。 初期化が行われない場合 が実行されない場合、オブジェクトは不定な値を持つ。 - エンドノート ]
  • それ以外の場合は 新イニシャライザー は、8.5の初期化のルールに従って解釈され 直接初期化 .

Default-initialization は [dcl.init]/7 で定義されています(C++11 では /6 で、この表現自体も同じ効果を持ちます)。

には デフォルト初期化 型のオブジェクトを T を意味します。

  • もし T が (cv で修飾された) クラス型である場合 (条項 9)、そのデフォルトコンストラクタ (12.1) は T が呼び出されます(そして,初期化 が不正確な場合 T がデフォルトコンストラクタやオーバーロードの解決を持たない場合 (13.3) の結果、曖昧になったり、削除された関数や 初期化のコンテキストからアクセスできない)。
  • もし T が配列型である場合、各要素は デフォルトで初期化される ;
  • を指定しない場合は、初期化を行いません。

このように

  • new A 単独で原因 A のデフォルトコンストラクタが呼び出されるだけで、そのコンストラクタが初期化されるわけではありません。 m . 不定値です。のはずです。 new B .
  • new A() は[dcl.init]/11(C++11では/10)に従って解釈されます。

    イニシャライザーが括弧の空集合であるオブジェクト、すなわち () であるオブジェクトは,値で初期化されなければならない。

    そして、次に [dcl.init]/8 (C++11† では /7) を考えてみましょう。

    には 値初期化 型のオブジェクトを T を意味します。

    • もし T が (cv-qualified) クラス型 (条項 9) で、デフォルトコンストラクタがない (12.1) か、デフォルトコンストラクタがユーザによって提供されるか削除されるかのいずれかである場合、オブジェクトはデフォルト初期化されます。 である場合、そのオブジェクトはデフォルトで初期化されます。
    • もし T が (おそらく cv-qualified) クラス型で、ユーザが用意した、あるいは削除されたデフォルトコンストラクタがない場合、そのオブジェクトは ゼロ初期化され、デフォルト初期化のためのセマンティック制約がチェックされます。 デフォルト初期化に関するセマンティック制約がチェックされ,T が自明でないデフォルトコンストラクタを持つ場合,オブジェクトはデフォルト初期化されます. コンストラクタがある場合、オブジェクトはデフォルト初期化されます。
    • もし T が配列型である場合、各要素は値で初期化されます。
    • でない場合は、オブジェクトはゼロ初期化されます。

    したがって new A() はゼロ初期化されます。 m . そして、これは次のように等価であるべきです。 AB .

  • new C そして new C() はオブジェクトを再びデフォルトで初期化します。なぜなら、最後の引用文の最初の箇条書きが適用されるからです (C にはユーザが提供するデフォルトのコンストラクタがあります!)。しかし、明らかに、今 m はどちらの場合もコンストラクタで初期化されます。


この段落は C++11 で若干異なる表現になっていますが、結果は変わりません。

には 値初期化 型のオブジェクトを T を意味します。

  • もし T が (おそらく cv-qualified) クラス型 (条項 9) であり、ユーザが提供するコンストラクタ (12.1) がある場合。 ユーザが提供するコンストラクタ (12.1) がある場合、デフォルトのコンストラクタは T のデフォルトコンストラクタが呼び出されます (そして、T がアクセス可能なデフォルトコンストラクタを持たない場合、初期化は不正な形式となります)。 のデフォルトコンストラクタがない場合、初期化は不正確です)。
  • もし T が (cv で修飾された) 非ユニオン型であり、ユーザが提供するコンストラクタがない場合 クラスであり、ユーザが提供するコンストラクタがない場合、オブジェクトはゼロ初期化されます。 ゼロ初期化され、もし T の暗黙のうちに宣言されたデフォルトコンストラクタが自明でない場合、そのオブジェクトはゼロ初期化されます。 が自明でない場合、そのコンストラクタが呼び出されます。
  • もし T が配列型である場合。 の場合、各要素は値で初期化されます。
  • それ以外の場合、オブジェクトは ゼロ初期化されます。