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