home | help
std::launder(3) 	       C++ Standard Libary		 std::launder(3)

NAME
     std::launder - std::launder

Synopsis
	Defined in header <new>
	template< class T >				      (since C++17)
	constexpr T* launder( T* p ) noexcept;		      (until C++20)
	template< class T >				      (since C++20)
	[[nodiscard]] constexpr T* launder( T* p ) noexcept;

	Provenance fence with respect to p. Returns a pointer to the same memory
     that p
	points	to,  but where the referent object is assumed to have a distinct
     lifetime and
	dynamic type.

	Formally, given

	  * the pointer p represents the address A of a byte in memory
	  * an object x is located at the address A
	  * x is within its lifetime
	  * the type of x is the same as  T,  ignoring	cv-qualifiers  at  every
     level
	  *  every  byte that would be reachable through the result is reachable
     through p
	    (bytes are reachable through a pointer that points to an object y if
     those bytes
	    are within the storage of an object z that is  pointer-interconvert-
     ible 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 ob-
     ject x.
	Otherwise, the behavior is undefined.

	The program is ill-formed if T is a function type or (possibly cv-quali-
     fied) void.

	std::launder may be used in a core 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.

Notes
	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 of std::launder include:

	  * Obtaining a pointer to an object created in the storage of an exist-
     ing object of
	    the same type, where pointers to the old  object  cannot  be  reused
     (for instance,
	    because either object is a base class subobject);
	  *  Obtaining	a  pointer  to an object created by placement 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

Example
     // Run this code

      #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 be-
     cause
	  // 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:	reinter-
     pret_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
      }

	Defect reports

	The following behavior-changing defect	reports  were  applied	retroac-
     tively to
	previously published C++ standards.

	   DR	 Applied to		 Behavior as published		    Cor-
     rect behavior
			    definition of reachable did not consider
	LWG  2859 C++17      pointer					     in-
     cluded
			    arithmetic from pointer-interconvertible object
	LWG 3495 C++17	    std::launder might make pointer to an inactive  for-
     bidden
			    member dereferenceable in constant expression

http://cppreference.com 	   2024.06.10			 std::launder(3)

home | help