Defined in header <new> | ||
|---|---|---|
template <class T> constexpr T* launder(T* p) noexcept; | (since C++17) (until C++20) | |
template <class T> [[nodiscard]] constexpr T* launder(T* p) noexcept; | (since C++20) |
Obtains a pointer to the object located at the address represented by p.
Formally, given.
p represents the address A of a byte in memory X is located at the address A X is within its lifetime X is the same as T, ignoring cv-qualifiers at every level Y if those bytes are within the storage of an object Z that is pointer-interconvertible with Y, or within the immediately enclosing array of which Z is an element) Then std::launder(p) returns a value of type T* that points to the object X. Otherwise, the behavior is undefined.
The program is ill-formed if T is a function type or (possibly cv-qualified) void.
std::launder may be used in a core constant expression if the value of its argument may be used in a core constant expression.
Typical uses of std::launder include:
const or reference data members, or because either object is a base class subobject; new from a pointer to an object providing storage for that object. The reachability restriction ensures that std::launder cannot be used to access bytes not accessible through the original pointer, thereby interfering with the compiler's escape analysis.
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 <new>
#include <cstddef>
#include <cassert>
struct X {
const int n; // note: X has a const member
int m;
};
struct Y {
int z;
};
struct A {
virtual int transmogrify();
};
struct B : A {
int transmogrify() override { new(this) A; return 2; }
};
int A::transmogrify() { new(this) B; return 1; }
static_assert(sizeof(B) == sizeof(A));
int main()
{
X *p = new X{3, 4};
const int a = p->n;
X* np = new (p) X{5, 6}; // p does not point to new object because X::n is const; np does
const int b = p->n; // undefined behavior
const int c = p->m; // undefined behavior (even though m is non-const, p can't be used)
const int d = std::launder(p)->n; // OK, std::launder(p) points to new object
const int e = np->n; // OK
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
A i;
int n = i.transmogrify();
// int m = i.transmogrify(); // undefined behavior
int m = std::launder(&i)->transmogrify(); // OK
assert(m + n == 3);
}
© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
http://en.cppreference.com/w/cpp/utility/launder