Namespaces
Variants

Lifetime

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

すべての object および reference には 生存期間 があります。これは実行時プロパティです:あらゆるオブジェクトまたは参照について、その生存期間が開始するプログラム実行の時点があり、終了する瞬間があります。

オブジェクトの生存期間は以下の時に開始されます:

  • オブジェクトが 共用体メンバー またはその部分オブジェクトである場合、その生存期間は、その共用体メンバーが共用体内で初期化されたメンバーである場合、またはアクティブにされた場合にのみ開始されます。
  • オブジェクトが共用体オブジェクト内にネストされている場合、包含する共用体オブジェクトが自明な特殊メンバー関数によって代入または構築されると、その生存期間が開始されることがあります。
  • 配列オブジェクトの生存期間は、 std::allocator::allocate によって割り当てられた場合にも開始されることがあります。

一部の操作は、指定された記憶域領域内で 暗黙的にオブジェクトを作成 し、その生存期間を開始します。暗黙的に作成されたオブジェクトの副オブジェクトが暗黙的生存期間型でない場合、その生存期間は暗黙的に開始されません。

オブジェクトの寿命が終了するのは以下の場合です:

  • 非クラス型の場合、オブジェクトは破棄される(擬似デストラクタ呼び出しを介して行われる可能性あり)、または
  • クラス型の場合、 destructor の呼び出しが開始される、または
  • オブジェクトが占有していた記憶域が解放される、またはその内部にネストされていないオブジェクトによって 再利用 される。

オブジェクトの生存期間は、そのストレージの生存期間と等しいか、またはその内部にネストされています。詳細は storage duration を参照してください。

参照の生存期間は、 reference の初期化が完了した時点で始まり、スカラーオブジェクトであるかのように終了します。

注意: 参照先オブジェクトの寿命が参照の寿命よりも先に終了する可能性があり、 ダングリング参照 が発生する可能性があります。

非静的データメンバと基底サブオブジェクトの生存期間は、 class initialization order に従って開始および終了します。

目次

一時オブジェクトの寿命

一時オブジェクトは、 prvalueが materialized されてglvalueとして使用可能になる際に生成され、これは以下の状況で発生します (since C++17)

(C++11以降)
  • 関数からのprvalueの返却
  • 変換 prvalueを生成する変換 ( 含む T ( a, b, c ) および T { } )
(C++11以降)
(C++17まで)

一時オブジェクトの実体化は、不必要な一時オブジェクトの作成を避けるために可能な限り遅延される: コピー省略 を参照。

(C++17以降)


T 型のオブジェクトが 潜在的に評価される 関数呼び出しで渡される、または返されるとき、 T が以下のいずれかの型である場合、実装は関数パラメータまたは結果オブジェクトを保持するための一時オブジェクトを作成することが許可されます:

(C++26以降)
  • 以下のすべての条件を満たすクラス型:
    • T が少なくとも1つの適格な コピー または ムーブ コンストラクタを持つ
    • T の各適格なコピー/ムーブコンストラクタが自明である
    • T デストラクタ が自明であるか削除されている

一時オブジェクトはそれぞれ関数引数または戻り値から構築され、関数のパラメータまたは戻り値オブジェクトは、適格な自明コンストラクタを使用して一時オブジェクトをコピーするかのように初期化されます(そのコンストラクタがアクセス不能であるか、オーバーロード解決によってオブジェクトのコピーまたはムーブを実行するために選択されない場合でも)。

(C++26以前)

一時オブジェクトは以下のように作成されます:

  • 最初の一時オブジェクトはそれぞれ関数引数または戻り値から構築されます
  • 各後続の一時オブジェクトは、 T がスカラ型の場合は 直接初期化 によって、それ以外の場合は適格な自明コンストラクタを使用して前の一時オブジェクトから初期化されます
  • 関数パラメータまたは戻り値オブジェクトは、 T がスカラ型の場合は直接初期化によって、それ以外の場合は適格な自明コンストラクタを使用して最後の一時オブジェクトから初期化されます

すべての場合において、そのコンストラクタがアクセス不能であるか、オーバーロード解決によってオブジェクトのコピーまたはムーブを実行するために選択されない場合でも、適格なコンストラクタが使用されます。

(C++26以降)

この自由度は、オブジェクトをレジスタで関数に渡したり返したりできるようにするために与えられています。

(C++17以降)

すべての一時オブジェクトは、それらが作成された位置を(字句的に)含む full-expression の評価の最終ステップとして破棄され、複数の一時オブジェクトが作成された場合、それらは作成順と逆の順序で破棄されます。これは、その評価が例外をスローして終了した場合でも同様です。

以下はその例外です:

  • 一時オブジェクトの寿命は参照へのバインドによって延長される場合があります。詳細は reference initialization を参照してください。
  • 配列の要素を初期化またはコピーするために使用されるデフォルトコンストラクタまたはコピーコンストラクタのデフォルト引数を評価する際に作成される一時オブジェクトの寿命は、配列の次の要素の初期化が開始される前に終了します。
  • ユニークな名前を持つ変数の初期化子によって導入される 構造化バインディング 宣言で作成された一時オブジェクトの寿命は、構造化バインディング宣言の終わりまで延長される。
(C++17以降)
  • 範囲 for 文の 範囲初期化子 で作成された一時オブジェクトの寿命は、本来 範囲初期化子 の終わりで破棄されるはずであったが、ループ本体の終わりまで延長される。
(C++23以降)

ストレージ再利用

プログラムは、オブジェクトが 自明に破棄可能 である場合(プログラムの正しい動作がデストラクタに依存する可能性があることに注意)、そのオブジェクトの寿命を終了させるためにデストラクタを呼び出す必要はありません。しかし、プログラムが非自明なデストラクタを持つオブジェクト(変数である場合)の寿命を明示的に終了させる場合、デストラクタが暗黙的に呼び出される前(すなわち、自動オブジェクトの場合はスコープ終了または例外による、 new 配置 スレッドローカルオブジェクトの場合はスレッド終了による、 (C++11以降) 静的オブジェクトの場合はプログラム終了による)に、同じ型の新しいオブジェクトをその場で構築する(例:配置 new を介して)ことを保証しなければなりません。そうでない場合、動作は未定義です。

class T {}; // trivial(自明)
struct B
{
    ~B() {} // non-trivial(非自明)
};
void x()
{
    long long n; // automatic(自動)、trivial(自明)
    new (&n) double(3.14); // 異なる型での再利用は問題なし
} // 問題なし
void h()
{
    B b; // automatic(自動)non-trivially destructible(非自明なデストラクタ)
    b.~B(); // 寿命終了(副作用がないため必須ではない)
    new (&b) T; // 誤った型:デストラクタが呼び出されるまでは問題なし
} // デストラクタが呼び出される:未定義動作

静的 , スレッドローカル, (C++11以降) または自動ストレージ期間を持つconst完全オブジェクトが占有していた(または占有している)ストレージを再利用することは未定義動作です。このようなオブジェクトは読み取り専用メモリに格納されている可能性があるためです:

struct B
{
    B(); // 非自明
    ~B(); // 非自明
};
const B b; // const static
void h()
{
    b.~B(); // bの生存期間を終了
    new (const_cast<B*>(&b)) const B; // 未定義動作: constオブジェクトの再利用の試み
}

new を評価する際、ストレージは アロケーション関数 から返された後に再利用されると見なされますが、new式の initializer の評価前になります:

struct S
{
    int m;
};
void f()
{
    S x{1};
    new(&x) S(x.m); // 未定義動作: ストレージが再利用されている
}

あるオブジェクトが占有していたアドレスに新しいオブジェクトが作成された場合、元のオブジェクトに対するすべてのポインタ、参照、および名前は自動的に新しいオブジェクトを参照するようになり、新しいオブジェクトの生存期間が開始されると、新しいオブジェクトを操作するために使用できるが、これは元のオブジェクトが新しいオブジェクトによって透過的に置換可能な場合に限られる。

以下のすべての条件が満たされる場合、オブジェクト x はオブジェクト y によって 透過的に置換可能 である:

  • y のストレージは、 x が占有していたストレージ位置と完全に重なっています。
  • y x と同じ型です(トップレベルのcv修飾子を無視します)。
  • x は完全なconstオブジェクトではありません。
  • x y も基底クラスのサブオブジェクト または [[ no_unique_address ]] で宣言されたメンバサブオブジェクトではありません (C++20以降)
  • 以下の条件のいずれかが満たされます:
  • x y は両方とも完全なオブジェクトである。
  • x y はそれぞれオブジェクト ox oy の直接の部分オブジェクトであり、 ox oy によって透過的に置換可能である。
struct C
{
    int i;
    void f();
    const C& operator=(const C&);
};
const C& C::operator=(const C& other)
{
    if (this != &other)
    {
        this->~C();          // *thisの生存期間が終了
        new (this) C(other); // 型Cの新しいオブジェクトが作成される
        f();                 // 明確に定義された動作
    }
    return *this;
}
C c1;
C c2;
c1 = c2; // 明確に定義された動作
c1.f();  // 明確に定義された動作; c1は型Cの新しいオブジェクトを参照

上記の条件が満たされない場合でも、ポインタ最適化バリア std::launder を適用することで、新しいオブジェクトへの有効なポインタを取得できる可能性があります:

struct A
{ 
    virtual int transmogrify();
};
struct B : A
{
    int transmogrify() override { ::new(this) A; return 2; }
};
inline int A::transmogrify() { ::new(this) B; return 1; }
void test()
{
    A i;
    int n = i.transmogrify();
    // int m = i.transmogrify(); // undefined behavior:
    // the new A object is a base subobject, while the old one is a complete object
    int m = std::launder(&i)->transmogrify(); // OK
    assert(m + n == 3);
}
(C++17以降)

同様に、クラスのメンバーまたは配列要素のストレージ内でオブジェクトが作成される場合、作成されたオブジェクトは、以下の条件を満たす場合にのみ元のオブジェクトの包含オブジェクトのサブオブジェクト(メンバーまたは要素)となります:

  • 包含オブジェクトの生存期間が開始され、終了していないこと
  • 新規オブジェクトのストレージが元のオブジェクトのストレージと正確に重なること
  • 新規オブジェクトが元のオブジェクトと同じ型であること(CV修飾を無視する)

それ以外の場合、元の部分オブジェクトの名前は std::launder なしでは新しいオブジェクトにアクセスするために使用できません:

(C++17以降)

ストレージの提供

特別なケースとして、オブジェクトは unsigned char または std::byte (C++17以降) の配列内で作成することができます (この場合、その配列はオブジェクトに対して ストレージを提供する と言われます) もし

  • 配列の生存期間が開始されておらず終了していない
  • 新しいオブジェクトのストレージが配列内に完全に収まる
  • これらの制約を満たす配列オブジェクトが配列内にネストされていない

配列のその部分が以前に別のオブジェクトにストレージを提供していた場合、そのストレージが再利用されたため、そのオブジェクトのライフタイムは終了します。ただし、配列自体のライフタイムは終了しません(そのストレージは再利用されたとは見なされません)。

template<typename... T>
struct AlignedUnion
{
    alignas(T...) unsigned char data[max(sizeof(T)...)];
};
int f()
{
    AlignedUnion<int, char> au;
    int *p = new (au.data) int;     // OK、au.dataがストレージを提供
    char *c = new (au.data) char(); // OK、*pの寿命を終了させる
    char *d = new (au.data + 1) char();
    return *c + *d; // OK
}

生存期間外へのアクセス

オブジェクトの生存期間が開始する前で、かつそのオブジェクトが占有する記憶域が割り当てられた後、または、オブジェクトの生存期間が終了した後で、かつそのオブジェクトが占有していた記憶域が再利用または解放される前に、そのオブジェクトを識別するglvalue式の以下の使用法の動作は、オブジェクトが構築中または破棄中である場合を除き(別個の規則が適用されます)、未定義です:

  1. オブジェクトにアクセスする。
  2. 非静的データメンバへのアクセス、または非静的メンバ関数の呼び出し。
  3. 仮想基底クラスのサブオブジェクトへの参照をバインドする。
  4. dynamic_cast または typeid 式。

上記の規則はポインタにも適用されます(仮想基底クラスへの参照の束縛は、仮想基底クラスへのポインタへの暗黙変換で置き換えられます)。これに加えて2つの追加規則があります:

  1. static_cast オブジェクトを持たないストレージへのポインタの変換は、(possibly cv-qualified) void * へのキャストの場合にのみ許可されます。
  2. オブジェクトを持たないストレージへのポインタで、possibly cv-qualified void * にキャストされたものは、possibly cv-qualified char へのポインタ、またはpossibly cv-qualified unsigned char 、またはpossibly cv-qualified std::byte (C++17以降) へのポインタにのみ static_cast できます。

構築および破壊中は、一般的に非静的メンバ関数の呼び出し、非静的データメンバへのアクセス、 typeid および dynamic_cast の使用が許可されています。しかし、ライフタイムがまだ開始されていない(構築中)か、すでに終了している(破壊中)ため、特定の操作のみが許可されます。一つの制限については、 構築および破壊中の仮想関数呼び出し を参照してください。

注記

CWG issue 2256 が解決されるまで、生存期間の終了規則は非クラスオブジェクト(ストレージ期間の終了)とクラスオブジェクト(構築の逆順)で異なります:

struct A
{
    int* p;
    ~A() { std::cout << *p; } // CWG2256以降は未定義動作: nはaよりも長生きしない
                              // CWG2256までは明確に定義: 123を出力
};
void f()
{
    A a;
    int n = 123; // nがaよりも長生きしない場合、これは最適化で除去される可能性がある(デッドストア)
    a.p = &n;
}

RU007 が解決されるまで、const修飾型または参照型の非静的メンバは、その包含オブジェクトが透過的に置換可能であることを妨げ、これにより std::vector および std::deque の実装が困難になります:

struct X { const int n; };
union U { X x; float f; };
void tong()
{
    U u = { {1} };
    u.f = 5.f;                          // OK: 'u'の新しいサブオブジェクトを作成
    X *p = new (&u.x) X {2};            // OK: 'u'の新しいサブオブジェクトを作成
    assert(p->n == 2);                  // OK
    assert(u.x.n == 2);                 // RU007までは未定義:
                                        // 'u.x'は新しいサブオブジェクトを指さない
    assert(*std::launder(&u.x.n) == 2); // RU007まででもOK
}

不具合報告

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

DR 適用対象 公開時の動作 正しい動作
CWG 119 C++98 非トリビアルコンストラクタを持つクラス型のオブジェクトは
コンストラクタ呼び出しが完了した時点でのみ生存期間が開始する
その他の初期化でも
生存期間が開始する
CWG 201 C++98 デフォルトコンストラクタのデフォルト引数内の一時オブジェクトの
生存期間は配列の初期化が完了した時点で終了する必要があった
次の要素の初期化前に
生存期間が終了する
( CWG issue 124 も解決)
CWG 274 C++98 生存期間外のオブジェクトを指す左辺値は、変換が最終的に
cv-unqualified char & または unsigned char & になる場合にのみ
static_castのオペランドとして使用可能
cv-qualified char &
および unsigned char &
も許可される
CWG 597 C++98 以下の動作は未定義であった:
1. 生存期間外のオブジェクトへのポインタが非仮想基底クラスへの
ポインタに暗黙変換される
2. 生存期間外のオブジェクトを参照する左辺値が非仮想基底クラスへの
参照にバインドされる
3. 生存期間外のオブジェクトを参照する左辺値が static_cast のオペランドとして
使用される(一部例外を除く)
適切に定義された動作となる
CWG 2012 C++98 参照の生存期間は記憶域期間と一致するように指定され、
extern参照はその初期化子が実行される前に生存している必要があった
初期化時に
生存期間が開始する
CWG 2107 C++98 CWG issue 124 の解決策がコピーコンストラクタに適用されなかった 適用される
CWG 2256 C++98 トリビアルに破棄可能なオブジェクトの生存期間が他のオブジェクトと矛盾していた 一貫性を持たせた
CWG 2470 C++98 複数の配列が同じオブジェクトに対して記憶域を提供できた 1つのみが提供する
CWG 2489 C++98 char [ ] は記憶域を提供できないが、オブジェクトは
その記憶域内に暗黙的に作成できた
オブジェクトは char [ ]
記憶域内に暗黙的に
作成できない
CWG 2527 C++98 記憶域の再利用によりデストラクタが呼び出されず、
プログラムがその副作用に依存する場合、動作は未定義であった
この場合の動作は
適切に定義される
CWG 2721 C++98 配置 new における記憶域再利用の正確な時点が不明確であった 明確化された
CWG 2849 C++23 関数パラメータオブジェクトは範囲 for ループの一時オブジェクト
生存期間延長のための一時オブジェクトと見なされていた
一時オブジェクトと
見なされない
CWG 2854 C++98 例外オブジェクトは一時オブジェクトであった 一時オブジェクトでは
ない
CWG 2867 C++17 構造化束縛宣言で作成された一時オブジェクトの生存期間が
延長されなかった
宣言の終わりまで
延長される
P0137R1 C++98 unsigned char の配列内にオブジェクトを作成するとその記憶域が再利用された 記憶域は再利用されない
P0593R6 C++98 擬似デストラクタ呼び出しには効果がなかった オブジェクトを破棄する
P1971R0 C++98 const修飾型または参照型の非静的データメンバが
その包含オブジェクトの透過的置換可能性を妨げていた
制限が削除された
P2103R0 C++98 透過的置換可能性は元の構造を保持する必要がなかった 必要とする

参考文献

  • C++23標準 (ISO/IEC 14882:2024):
  • 6.7.3 オブジェクト生存期間 [basic.life]
  • 11.9.5 構築と破棄 [class.cdtor]
  • C++20標準 (ISO/IEC 14882:2020):
  • 6.7.3 オブジェクト生存期間 [basic.life]
  • 11.10.4 構築と破棄 [class.cdtor]
  • C++17規格 (ISO/IEC 14882:2017):
  • 6.8 オブジェクト生存期間 [basic.life]
  • 15.7 構築と破棄 [class.cdtor]
  • C++14 標準 (ISO/IEC 14882:2014):
  • 3 オブジェクト生存期間 [basic.life]
  • 12.7 構築と破棄 [class.cdtor]
  • C++11標準 (ISO/IEC 14882:2011):
  • 3.8 オブジェクト生存期間 [basic.life]
  • 12.7 構築と破棄 [class.cdtor]
  • C++03規格 (ISO/IEC 14882:2003):
  • 3.8 オブジェクト生存期間 [basic.life]
  • 12.7 構築と破棄 [class.cdtor]
  • C++98 標準 (ISO/IEC 14882:1998):
  • 3.8 オブジェクト生存期間 [basic.life]
  • 12.7 構築と破棄 [class.cdtor]

関連項目

C documentation for Lifetime