|
|
|
|
Defined in header <new> | ||
template<class T> constexpr T* launder( T* p)noexcept; | (since C++17) | |
Devirtualization fence with respect top. Returns a pointer to an object at the same address thatp represents, while the object can be a new base class subobject whose most derived class is different from that of the original*p object.
Formally, given
A
of a byte in memoryA
T
, ignoring cv-qualifiers at every levelThenstd::launder(p) returns a value of typeT*
that points to the objectx. Otherwise, the behavior is undefined.
The program is ill-formed ifT
is a function type or (possibly cv-qualified)void.
std::launder
may be used in acore constant expression if and only if the (converted) value of its argument may be used in place of the function invocation. In other words,std::launder
does not relax restrictions in constant evaluation.
std::launder
has no effect on its argument. Its return value must be used to access the object. Thus, it's always an error to discard the return value.
Typical uses ofstd::launder
include:
new
from a pointer to an object providing storage for that object.Thereachability restriction ensures thatstd::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 paddingauto p3= std::launder(reinterpret_cast<int(*)[10]>(&x3.a[0]));// OKauto 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{virtualint transmogrify();}; struct Derived: Base{int transmogrify() override{ new(this) Base;return2;}}; int Base::transmogrify(){ new(this) Derived;return1;} 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 behaviorint m= std::launder(&base)->transmogrify();// OKassert(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};constint 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 objectconstint g= q->z;// OKconstint h= std::launder(reinterpret_cast<Y*>(&s))->z;// OK [](...){}(f, g, h);// evokes [[maybe_unused]] effect}
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
DR | Applied to | Behavior as published | Correct behavior |
---|---|---|---|
LWG 2859 | C++17 | definition ofreachable did not consider pointer arithmetic from pointer-interconvertible object | included |
LWG 3495 | C++17 | std::launder might make pointer to an inactivemember dereferenceable in constant expression | forbidden |