Namespaces
Variants

Default-initialization

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

これは、初期化子なしでオブジェクトが構築された際に実行される初期化です。

目次

構文

T object  ; (1)
new T (2)

説明

デフォルト初期化は以下の3つの状況で実行されます:

1) 自動、静的、またはスレッドローカルの storage duration を持つ変数が初期化子なしで宣言された場合;
2) 動的ストレージ期間を持つオブジェクトが初期化子なしの new-expression によって作成された場合;
3) 基底クラスまたは非静的データメンバが constructor initializer list で明示されず、そのコンストラクタが呼び出された場合。

デフォルト初期化の効果は以下の通りです:

  • T が(CV修飾の可能性がある) 非POD (C++11まで) クラス型の場合、コンストラクタが考慮され、 オーバーロード解決 が空の引数リストに対して実行される。選択されたコンストラクタ( デフォルトコンストラクタ の一つ)が呼び出され、新しいオブジェクトの初期値が提供される;
  • T が配列型の場合、配列の各要素がデフォルト初期化される;
  • それ以外の場合、初期化は行われない( 注記 を参照)。

constオブジェクトのデフォルト初期化

プログラムが const 修飾型 T のオブジェクトのデフォルト初期化を要求する場合、Tは const-default-constructible なクラス型またはその配列でなければならない。

const-default-constructibleなクラス型 T とは、 T のデフォルト初期化が T のユーザー提供コンストラクタを呼び出す場合 (基底クラスから継承されたものではない) (C++11以降) または

初期化子が使用されない場合、自動記憶域期間を持つ(おそらくcv修飾された)非PODクラス型(またはその配列)のみがデフォルト初期化されると見なされていました。動的記憶域期間を持つスカラー型とPOD型は初期化されていないと見なされていました(C++11以降、この状況はデフォルト初期化の一形態として再分類されました)。

(until C++11)
  • T の各直接非静的データメンバー M がクラス型 X (またはその配列)であり、 X がconst-default-constructibleであり、かつ
  • T が直接の variant members を持たない、かつ
(C++11まで)
  • T の各直接非variant非静的データメンバー M default member initializer を持つか、または M がクラス型 X (またはその配列)である場合、 X がconst-default-constructibleであり、
  • T が少なくとも1つの非静的データメンバーを持つunionである場合、正確に1つの variant member がdefault member initializerを持ち、
  • T がunionでない場合、少なくとも1つの非静的データメンバーを持つ各匿名unionメンバー(存在する場合)について、正確に1つの非静的データメンバーがdefault member initializerを持つ、かつ
(C++11以降)

T の各 潜在的に構築される 基底クラスがconst-default-constructibleである。

不定値および誤った値

自動または動的ストレージ期間を持つオブジェクトのストレージが取得されると、そのオブジェクトは 不定値 を持つ。

オブジェクトに対して初期化が行われない場合、そのオブジェクトは値が置き換えられるまで不定値を保持する。

(C++26まで)

自動または動的ストレージ期間を持つオブジェクトのストレージが取得されると、オブジェクトのストレージを構成するバイトは以下の初期値を持つ:

  • オブジェクトが動的ストレージ期間を持つ場合、または最初の宣言が [[ indeterminate ]] でマークされた変数または 関数パラメータ に関連付けられたオブジェクトである場合、バイトは 不定値 を持つ。
  • それ以外の場合、バイトは 誤った値 を持ち、各値はプログラムの状態とは独立して実装によって決定される。

オブジェクト( 部分オブジェクト を含む)に対して初期化が行われない場合、そのようなバイトは値が置き換えられるまで初期値を保持する。

  • 値表現 内の任意のビットが不定値を持つ場合、オブジェクトは 不定値 を持つ。
  • それ以外の場合、値表現内の任意のビットが誤った値を持つ場合、オブジェクトは 誤った値 を持つ。
(C++26以降)

評価が不定値を生成する場合、その動作は undefined です。

評価が誤った値を生成する場合、その動作は 誤った動作 となります。

(C++26以降)

特殊ケース

以下の型は uninitialized-friendly です:

(C++17以降)
  • unsigned char
  • char 、その基盤となる型が unsigned char である場合

不定の または誤った (C++26以降) value が与えられたとき、 value 未初期化結果値 は以下の通りです:

  • 不定値、もし value も不定値である場合。
  • value 、もし value が誤った値である場合。
(C++26以降)

評価 eval が初期化未対応フレンドリー型の不定 または誤った (C++26以降) value を生成する場合、以下のケースでは動作は明確に定義されます:

  • eval は以下の式とオペランドのいずれかの評価です:
  • 条件式の第2または第3オペランド。
  • コンマ式の右オペランド。
  • 整数変換、明示的キャスト、または初期化不要フレンドリー型への static_cast のオペランド。
  • 破棄値式。
この場合、演算の結果は value の未初期化結果値となります。
  • eval は、左オペランドが初期化フレンドリー型の左辺値である 単純代入演算子 の右オペランドの評価です。
この場合、左オペランドによって参照されるオブジェクトの値は、 value の未初期化結果値によって置き換えられます。
  • eval は、初期化されていないフレンドリー型のオブジェクトを初期化する際の初期化式の評価です。
  • value は、初期化されるオブジェクトが std::byte 型でない場合、 std::byte 型にすることはできません。
(C++17以降)
この場合、そのオブジェクトは value の未初期化結果値で初期化されます。

初期化に寛容な型の不定値の変換は、不定値を生成します。

未初期化フレンドリー型の不正な値を変換すると不正な値が生成され、変換の結果は変換されたオペランドの値となります。

(C++26以降)
// ケース1: 動的記憶域期間を持つ未初期化オブジェクト
// 全C++バージョン: 不定値 + 未定義動作
int f(bool b)
{
    unsigned char* c = new unsigned char;
    unsigned char d = *c; // OK、「d」は不定値を持つ
    int e = d;            // 未定義動作
    return b ? d : 0;     // 「b」がtrueの場合、未定義動作
}
// ケース2: 自動記憶域期間を持つ未初期化オブジェクト
// C++26まで: 不定値 + 未定義動作
// C++26以降: 誤った値 + 誤った動作
int g(bool b)
{
    unsigned char c;     // 「c」は不定値/誤った値を持つ
    unsigned char d = c; // 未定義動作/誤った動作なし、
                         // ただし「d」は不定値/誤った値を持つ
    assert(c == d);      // 成立するが、両方の整数昇格は
                         // 未定義動作/誤った動作を持つ
    int e = d;           // 未定義動作/誤った動作
    return b ? d : 0;    // 「b」がtrueの場合、未定義動作/誤った動作
}
// ケース2と同じ
void h()
{
    int d1, d2;  // 「d1」と「d2」は不定値/誤った値を持つ
    int e1 = d1; // 未定義動作/誤った動作
    int e2 = d1; // 未定義動作/誤った動作
    assert(e1 == e2); // 成立
    assert(e1 == d1); // 成立、未定義動作/誤った動作
    assert(e2 == d1); // 成立、未定義動作/誤った動作
    // 未定義動作/誤った動作なし、
    // ただし「d2」は不定値/誤った値を持つ
    std::memcpy(&d2, &d1, sizeof(int));
    assert(e1 == d2); // 成立、未定義動作/誤った動作
    assert(e2 == d2); // 成立、未定義動作/誤った動作
}

注記

参照とconstスカラーオブジェクトはデフォルト初期化できません。

機能テストマクロ 規格 機能
__cpp_constexpr 201907L (C++20) constexpr関数での自明なデフォルト初期化と asm宣言

#include <string>
struct T1 { int mem; };
struct T2
{
    int mem;
    T2() {} // 「mem」は初期化子リストに含まれていない
};
int n; // 静的非クラス型、二段階初期化が行われる:
       // 1) ゼロ初期化によりnはゼロに初期化される
       // 2) デフォルト初期化は何もせず、nはゼロのまま
int main()
{
    [[maybe_unused]]
    int n;            // 非クラス型、値は不定
    std::string s;    // クラス型、デフォルトコンストラクタを呼び出し、値は""
    std::string a[2]; // 配列、要素をデフォルト初期化し、値は{"", ""}
//  int& r;           // エラー:参照
//  const int n;      // エラー:const非クラス型
//  const T1 t1;      // エラー:暗黙のデフォルトコンストラクタを持つconstクラス
    [[maybe_unused]]
    T1 t1;            // クラス型、暗黙のデフォルトコンストラクタを呼び出す
    const T2 t2;      // constクラス型、ユーザー提供のデフォルトコンストラクタを呼び出す
                      // t2.memはデフォルト初期化される
}

欠陥報告

以下の動作変更欠陥報告書は、以前に公開された C++ 標準に対して遡及的に適用されました。

DR 適用対象 公開時の動作 正しい動作
CWG 178 C++98 値初期化が存在しなかった;
空の初期化子はデフォルト初期化を呼び出した
(ただし new T ( ) はゼロ初期化も実行する)
空の初期化子は
値初期化を呼び出す
CWG 253 C++98 constオブジェクトのデフォルト初期化では
暗黙的に宣言されたデフォルトコンストラクタを呼び出せなかった
すべてのサブオブジェクトが初期化される場合は許可される
CWG 616 C++98 未初期化オブジェクトの左辺値から右辺値への変換は
常に未定義動作だった
不定値の unsigned char は許可される
CWG 1787 C++98 不定値の unsigned char からの読み取りが
レジスタにキャッシュされる場合は未定義動作だった
明確に定義された動作に変更

関連項目