web-dev-qa-db-ja.com

デフォルト、値、ゼロの初期化混乱

値とデフォルトとゼロの初期化について非常に混乱しています。特に、異なる標準C++ およびC++ 11(およびC++ 14)を採用した場合。

私は引用して本当に良い答えを拡張しようとしています Value-/Default-/Zero- Init C++ 98 and C++ 誰かが必要なギャップを埋めて何がいつ起こるかについての良い概要を手伝うことができれば多くのユーザーを助けるので、より一般的にするためにここに?

一例での完全な洞察:

New演算子によって返されるメモリが初期化されることもあれば、更新する型が POD(plain old data) であるかどうか、またはそれがクラスであるかどうかに依存しないこともあります。 PODメンバーを含み、コンパイラー生成のデフォルトコンストラクターを使用しています。

  • C++ 1998には、2つのタイプの初期化があります:zero-およびdefault-initialization
  • C++ 20の3番目のタイプの初期化では、value-initializationが追加されました。
  • C++ 2011/C++ 2014のみlist-initializationが追加され、value-/default-/zero-initializationのルールが追加されました少し変わった。

仮定:

_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()-value-initialize A。これはPODであるためゼロで初期化されます。
  • _new B_-デフォルトの初期化(_B::m_は初期化せず、BはPOD以外)
  • new B()-値の初期化Bは、デフォルトのctorがユーザー定義ではなくコンパイラ生成されるため、すべてのフィールドをゼロで初期化します。
  • _new C_-デフォルトのctorを呼び出すCをデフォルトで初期化します。 (_C::m_はゼロで初期化され、Cは非PODです)
  • new C()-デフォルトのctorを呼び出すCの値を初期化します。 (_C::m_はゼロで初期化されます)
  • _new D_-デフォルトの構成(_D::m_は初期化されていない、Dは非POD)
  • new D()-value-initializes D?、これはデフォルトのctorを呼び出します(_D::m_は初期化されていません)

斜体の値と?不確実性は、これを修正するのを手伝ってください:-)

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

??? (私がここから始めたら、とにかくうまくいかないので助けてください)

C++ 14準拠のコンパイラでは、次のように動作するはずです:??? (私がここから始めると、とにかく間違ってしまいます)(回答に基づいたドラフト)

  • _new A_-A、コンパイラーgenをデフォルトで初期化します。 ctor、(leavs _A::m_ uninitialized)(AはPODです)
  • new A()-Aの値を初期化します。これは、2以来のゼロ初期化です。[dcl.init]/8

  • _new B_-B、コンパイラーgenをデフォルトで初期化します。 ctor、(leavs _B::m_ uninitialized)(Bは非PODです)

  • new B()-値の初期化Bは、デフォルトのctorがユーザー定義ではなくコンパイラ生成されるため、すべてのフィールドをゼロで初期化します。
  • _new C_-デフォルトのctorを呼び出すCをデフォルトで初期化します。 (_C::m_はゼロで初期化され、Cは非PODです)
  • new C()-デフォルトのctorを呼び出すCの値を初期化します。 (_C::m_はゼロで初期化されます)
  • _new D_-Dをデフォルトで初期化します(_D::m_は初期化されず、Dは非PODです)
  • new D()-値の初期化Dは、デフォルトのctorを呼び出します(_D::m_は初期化されていません)
  • _new E_-compを呼び出すEをデフォルトで初期化します。 gen。俳優。 (_E::m_は初期化されておらず、Eは非PODです)
  • new E()-値の初期化E。これは、[dcl.init]/8の2ポイント以降のEをゼロで初期化します。
  • _new F_-compを呼び出すFをデフォルトで初期化します。 gen。俳優。 (_F::m_は初期化されていない、Fは非POD)
  • new F()-value-initializes F、これはdefault-initializesFから1を指しています- [dcl.init]/8F ctor関数は、ユーザーが宣言し、最初の宣言で明示的にデフォルト設定または削除されていない場合、ユーザーが提供します。 Link
80
Gabriel

C++ 14は、[expr.new]/17のnew(C++ 11の[expr.new]/15で作成されたオブジェクトの初期化を指定します。メモはメモではなく、規範的なテキストでした。その後):

タイプTのオブジェクトを作成するnew-expressionは、そのオブジェクトを次のように初期化します。

  • new-initializerが省略されている場合、オブジェクトはdefault-initialized(8.5)です。 [注:初期化が実行されない場合、オブジェクトの値は不確定です。 —終了ノート]
  • それ以外の場合、new-initializerは、direct-initializationの8.5の初期化ルールに従って解釈されます。

デフォルトの初期化は[dcl.init]/7で定義されています(C++ 11の場合は/ 6、文言自体にも同じ効果があります):

タイプTのオブジェクトをdefault-initializeするには、次のことを意味します。

  • Tが(おそらくcvで修飾された)クラス型(9項)の場合、Tのデフォルトコンストラクター(12.1)が呼び出されます(Tにはデフォルトのコンストラクタがないか、オーバーロード解決(13.3)があり、曖昧さや、初期化のコンテキストから削除された、またはアクセスできない関数になります。
  • Tが配列型の場合、各要素はdefault-initialized;
  • それ以外の場合、初期化は実行されません。

かくして

  • _new A_は、Asのデフォルトコンストラクターのみを呼び出し、mを初期化しません。不定値。 _new B_でも同じである必要があります。
  • new A()は[dcl.init]/11に従って解釈されます(C++ 11では/ 10):

    イニシャライザが空の括弧のセット、つまり_()_であるオブジェクトは、値で初期化されます。

    次に、[dcl.init]/8(C++ 11†の/ 7)を検討します。

    タイプTのオブジェクトをvalue-initializeするには、次のことを意味します。

    • Tが(おそらくcvで修飾された)クラス型(9項)であり、デフォルトコンストラクター(12.1)がないか、ユーザーが提供または削除するデフォルトコンストラクターの場合、オブジェクトはデフォルトで初期化されます。
    • _Tがユーザー提供または削除されたデフォルトコンストラクターのない(おそらくcv修飾)クラスタイプである場合、オブジェクトはゼロで初期化され、デフォルトの初期化のセマンティック制約がチェックされ、 Tに重要なデフォルトコンストラクターがある場合、オブジェクトはデフォルトで初期化されます;
    • Tが配列型の場合、各要素は値で初期化されます。
    • それ以外の場合、オブジェクトはゼロで初期化されます。

    したがって、new A()mをゼロで初期化します。そして、これはABで同等でなければなりません。

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


†さて、この段落にはC++ 11でわずかに異なる表現がありますが、結果は変わりません:

タイプTのオブジェクトをvalue-initializeするには、次のことを意味します。

  • Tが(ユーザー定義のコンストラクター(12.1)を持つ(おそらくcvで修飾された)クラス型(9節)である場合、Tのデフォルトコンストラクターが呼び出されます(初期化は不正です) -Tにアクセス可能なデフォルトコンストラクターがない場合)
  • Tが(ユーザー定義のコンストラクタを持たない(おそらくcvで修飾された)非共用クラス型である場合、オブジェクトはゼロで初期化され、Tの暗黙的に宣言されたデフォルトコンストラクタがnon -自明、そのコンストラクタが呼び出されます。
  • Tが配列型の場合、各要素は値で初期化されます。
  • それ以外の場合、オブジェクトはゼロで初期化されます。
24
Columbo