名前空間
変種
操作

std::launder

From cppreference.com
< cpp‎ | utility
 
 
ユーティリティライブラリ
言語サポート
型のサポート (基本型、RTTI)
ライブラリ機能検査マクロ (C++20)
プログラムユーティリティ
可変引数関数
コルーチンサポート (C++20)
契約サポート (C++26)
三方比較
(C++20)
(C++20)(C++20)(C++20)  
(C++20)(C++20)(C++20)

汎用ユーティリティ
関係演算子 (C++20で非推奨)
 
メモリ管理ライブラリ
(説明用*)
未初期化メモリのアルゴリズム
(C++17)
(C++17)
(C++17)
制約付き未初期化
メモリアルゴリズム
Cライブラリ

アロケータ
メモリリソース
ガベージコレクションのサポート
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
(C++11)(C++23まで)
未初期化ストレージ
(C++20まで*)
(C++20まで*)
明示的な生存期間管理
 
 
ヘッダ <new> で定義
template< class T >
constexpr T* launder( T* p ) noexcept;
(C++17以降)

pに関するデバーチャライゼーションフェンス。オブジェクトが元の*pオブジェクトの最も派生したクラスとは異なる新しい基底クラスサブオブジェクトである可能性がある間、pが表すのと同じアドレスにあるオブジェクトへのポインタを返します。

形式的には、以下が与えられた場合:

  • ポインタpはメモリ内のバイトAのアドレスを表す
  • オブジェクトxがアドレスAに位置する
  • xがそのライフタイム内にある
  • xの型が、すべてのレベルでのcv-修飾子を無視してTと同じである
  • 結果を介して到達可能なすべてのバイトがpを介して到達可能である(ポインタがオブジェクトyを指す場合、それらのバイトがyポインタ相互変換可能なオブジェクトzのストレージ内にあるか、またはzが要素である直近の包含配列内にある場合、それらのバイトはポインタを介して到達可能である)。

その場合、std::launder(p)はオブジェクトxを指す型T*の値を返します。それ以外の場合、動作は未定義です。

Tが関数型であるか、(cv修飾されている可能性のある)voidである場合、プログラムは不正です。

std::launderは、その引数の(変換された)値が関数呼び出しの代わりに使用できる場合にのみ、コア定数式で使用できます。言い換えれば、std::launderは定数評価における制限を緩和しません。

[編集] 備考

std::launderは引数に影響を与えません。その戻り値はオブジェクトにアクセスするために使用されなければなりません。したがって、戻り値を破棄することは常にエラーです。

std::launderの一般的な使用例には以下が含まれます。

  • 同じ型の既存のオブジェクトのストレージ内に作成されたオブジェクトへのポインタを取得する場合、古いオブジェクトへのポインタが再利用できない場合(たとえば、どちらかのオブジェクトが基底クラスのサブオブジェクトであるため)。
  • オブジェクトのストレージを提供するオブジェクトへのポインタから、配置newによって作成されたオブジェクトへのポインタを取得する場合。

到達可能性の制限は、std::launderが元のポインタを介してアクセスできないバイトにアクセスすることを防ぎ、それによってコンパイラの脱出解析を妨げないようにします。

int x[10];
auto p = std::launder(reinterpret_cast<int(*)[10]>(&x[0])); // OK
 
int x2[2][10];
auto p2 = std::launder(reinterpret_cast<int(*)[10]>(&x2[0][0]));
// Undefined behavior: x2[1] would be reachable through the resulting pointer to x2[0]
// but is not reachable from the source
 
struct X { int a[10]; } x3, x4[2]; // standard layout; assume no padding
auto p3 = std::launder(reinterpret_cast<int(*)[10]>(&x3.a[0])); // OK
auto p4 = std::launder(reinterpret_cast<int(*)[10]>(&x4[0].a[0]));
// Undefined behavior: x4[1] would be reachable through the resulting pointer to x4[0].a
// (which is pointer-interconvertible with x4[0]) but is not reachable from the source
 
struct Y { int a[10]; double y; } x5;
auto p5 = std::launder(reinterpret_cast<int(*)[10]>(&x5.a[0]));
// Undefined behavior: x5.y would be reachable through the resulting pointer to x5.a
// but is not reachable from the source

[編集]

#include <cassert>
#include <cstddef>
#include <new>
 
struct Base
{
    virtual int transmogrify();
};
 
struct Derived : Base
{
    int transmogrify() override
    {
        new(this) Base;
        return 2;
    }
};
 
int Base::transmogrify()
{
    new(this) Derived;
    return 1;
}
 
static_assert(sizeof(Derived) == sizeof(Base));
 
int main()
{
    // Case 1: the new object failed to be transparently replaceable because
    // it is a base subobject but the old object is a complete object.
    Base base;
    int n = base.transmogrify();
    // int m = base.transmogrify(); // undefined behavior
    int m = std::launder(&base)->transmogrify(); // OK
    assert(m + n == 3);
 
    // Case 2: access to a new object whose storage is provided
    // by a byte array through a pointer to the array.
    struct Y { int z; };
    alignas(Y) std::byte s[sizeof(Y)];
    Y* q = new(&s) Y{2};
    const int f = reinterpret_cast<Y*>(&s)->z; // Class member access is undefined
                                               // behavior: reinterpret_cast<Y*>(&s)
                                               // has value "pointer to s" and does
                                               // not point to a Y object
    const int g = q->z; // OK
    const int h = std::launder(reinterpret_cast<Y*>(&s))->z; // OK
 
    [](...){}(f, g, h); // evokes [[maybe_unused]] effect
}

[編集] 欠陥報告

以下の動作変更を伴う欠陥報告が、以前に公開されたC++標準に遡って適用されました。

DR 適用対象 公開された動作 正しい動作
LWG 2859 C++17 到達可能の定義はポインタを考慮していなかった
ポインタ相互変換可能なオブジェクトからの算術
含まれた
LWG 3495 C++17 std::launderは非アクティブなメンバーへのポインタを
定数式で逆参照可能にする可能性がある
禁止
English 日本語 中文(简体) 中文(繁體)