Namespaces
Variants
Views
Actions

Difference between revisions of "cpp/memory/start lifetime as"

From cppreference.com
< cpp‎ | memory
(crated->created. Since I found it twice, I have to wonder if it is correct, but I'll assume it's not)
m (Example: in-house fmt: +'\n')
 
(30 intermediate revisions by 16 users not shown)
Line 3: Line 3:
 
{{dcl begin}}
 
{{dcl begin}}
 
{{dcl header|memory}}
 
{{dcl header|memory}}
{{dcl h| start_lifetime_as}}
+
{{dcl h|{{tt|std::start_lifetime_as}}}}
 
{{dcl|num=1|since=c++23|1=
 
{{dcl|num=1|since=c++23|1=
template<class T>
+
template< class T >
  T* start_lifetime_as(void* p) noexcept;
+
T* start_lifetime_as( void* p ) noexcept;
 
}}
 
}}
 
{{dcl|num=2|since=c++23|1=
 
{{dcl|num=2|since=c++23|1=
template<class T>
+
template< class T >
  const T* start_lifetime_as(const void* p) noexcept;
+
const T* start_lifetime_as( const void* p ) noexcept;
 
}}
 
}}
 
{{dcl|num=3|since=c++23|1=
 
{{dcl|num=3|since=c++23|1=
template<class T>
+
template< class T >
  volatile T* start_lifetime_as(volatile void* p) noexcept;
+
volatile T* start_lifetime_as( volatile void* p ) noexcept;
 
}}
 
}}
 
{{dcl|num=4|since=c++23|1=
 
{{dcl|num=4|since=c++23|1=
template<class T>
+
template< class T >
  const volatile T* start_lifetime_as(const volatile void* p) noexcept;
+
const volatile T* start_lifetime_as( const volatile void* p ) noexcept;
 
}}
 
}}
{{dcl h| start_lifetime_as_array}}
+
{{dcl h|{{tt|std::start_lifetime_as_array}}}}
 
{{dcl|num=5|since=c++23|1=
 
{{dcl|num=5|since=c++23|1=
template<class T>
+
template< class T >
  T* start_lifetime_as_array(void* p, std::size_t n) noexcept;
+
T* start_lifetime_as_array( void* p, std::size_t n ) noexcept;
 
}}
 
}}
 
{{dcl|num=6|since=c++23|1=
 
{{dcl|num=6|since=c++23|1=
template<class T>
+
template< class T >
  const T* start_lifetime_as_array(const void* p,  
+
const T* start_lifetime_as_array( const void* p,
                                  std::size_t n) noexcept;
+
                                  std::size_t n ) noexcept;
 
}}
 
}}
 
{{dcl|num=7|since=c++23|1=
 
{{dcl|num=7|since=c++23|1=
template<class T>
+
template< class T >
  volatile T* start_lifetime_as_array(volatile void* p,
+
volatile T* start_lifetime_as_array( volatile void* p,
                                      std::size_t n) noexcept;
+
                                    std::size_t n ) noexcept;
 
}}
 
}}
 
{{dcl|num=8|since=c++23|1=
 
{{dcl|num=8|since=c++23|1=
template<class T>
+
template< class T >
  const volatile T* start_lifetime_as_array(const volatile void* p,  
+
const volatile T* start_lifetime_as_array( const volatile void* p,
                                            std::size_t n) noexcept;
+
                                          std::size_t n ) noexcept;
 
}}
 
}}
 
{{dcl end}}
 
{{dcl end}}
  
@1-4@ [[cpp/language/object#Object creation|Implicity creates]] a complete object of type {{tt|T}} whose address is {{tt|p}} and objects nested within it. The value of each created object {{tti|o}} of {{named req|TriviallyCopyable}} type {{tt|U}} is determined in the same manner as for a call to {{c|std::bit_cast<U>(E)}} except the storage is not really accessed, where {{tt|E}} is the lvalue of type {{tt|U}} denoting {{tti|o}}. Otherwise the value of such created objects are unspecified.
+
@1-4@ [[cpp/language/object#Object creation|Implicitly creates]] a complete object of type {{tt|T}} (whose address is {{c|p}}) and objects nested within it. The value of each created object {{tti|obj}} of {{named req|TriviallyCopyable}} type {{tt|U}} is determined in the same manner as for a call to {{c|std::bit_cast<U>(E)}} except that the storage is not actually accessed, where {{tt|E}} is the lvalue of type {{tt|U}} denoting {{tti|obj}}. Otherwise, the values of such created objects are unspecified.
* {{tt|T}} shall be an {{named req|ImplicitLifetimeType}} and shall not an incomplete type, otherwise the program is ill-formed.
+
* {{tt|T}} shall be an {{named req|ImplicitLifetimeType}} and shall be a [[cpp/language/type#Incomplete type|complete type]]. Otherwise, the program is ill-formed.
 
* The behavior is undefined if:
 
* The behavior is undefined if:
:* {{range|p|(char*)p + sizeof(T)}} does not denote a region of allocated storage that is a subset of the region of storage reachable through {{tt|p}}, or
+
:* {{range|p|(char*)p + sizeof(T)}} does not denote a region of allocated storage that is a subset of the region of storage reachable through {{c|p}}, or
 
:* the region is not suitably aligned for the {{tt|T}}.
 
:* the region is not suitably aligned for the {{tt|T}}.
 
* Note that the unspecified value can be indeterminate.
 
* Note that the unspecified value can be indeterminate.
@5-8@ [[cpp/language/object#Object creation|Implicity creates]] an object array of type {{tt|T}} with length {{tt|n}}. To be precise, if {{c|n > 0}} is {{c|true}}, it's equivalent to {{c|std::start_lifetime_as<U>(p)}} where {{tt|U}} is the type "array of {{tt|n}} {{tt|T}}". Otherwise, the function has no effects.
+
@5-8@ [[cpp/language/object#Object creation|Implicitly creates]] an array with element type {{tt|T}} and length {{c|n}}. To be precise, if {{c|n > 0}} is {{c|true}}, it is equivalent to {{c|std::start_lifetime_as<U>(p)}} where {{tt|U}} is the type "array of {{c|n}} {{tt|T}}s". Otherwise, the function has no effects.
* {{tt|T}} shall be a complete type, otherwise the program is ill-formed.
+
* {{tt|T}} shall be a [[cpp/language/type#Incomplete type|complete type]]. Otherwise, the program is ill-formed.
 
* The behavior is undefined if:
 
* The behavior is undefined if:
:* Non-null {{tt|p}} is not suitably aligned for an array of {{tt|T}}, or
+
:* Non-null {{c|p}} is not suitably aligned for an array of {{tt|T}}, or
:* {{c|n <{{=}} std::size_t(-1) / sizeof(T)}} is {{c|false}}, or
+
:* {{c|1=n <= std::size_t(-1) / sizeof(T)}} is {{c|false}}, or
:* {{c|n > 0}} and {{range|(char*)p|(char*)p + (n * sizeof(T))}} does not denote a region of allocated storage that is a subset of the region of storage reachable through {{tt|p}}.
+
:* {{c|n > 0}} and {{range|(char*)p|(char*)p + (n * sizeof(T))}} does not denote a region of allocated storage that is a subset of the region of storage reachable through {{c|p}}.
  
 
===Parameters===
 
===Parameters===
 
{{par begin}}
 
{{par begin}}
{{par | p | possible cv-qualified {{c|void}} pointer, denotes the address of the region consisting objects}}
+
{{par|p|the address of the region consisting objects}}
{{par | n | {{c|std::size_t}}, denotes the size of the object array to be created}}
+
{{par|n|the number of the element of the array to be created}}
{{par end}}  
+
{{par end}}
 
+
  
 
===Return value===
 
===Return value===
@1-4@ A pointer to the complete object described above;
+
@1-4@ A pointer to the complete object as described above.
@5-8@ A pointer to the first element of the created array, if any; otherwise, a pointer that compares equal to {{tt|p}}.  
+
@5-8@ A pointer to the first element of the created array, if any; otherwise, a pointer that compares equal to {{c|p}}.
 +
 
 +
===Notes===
 +
{{c|new (void_ptr) unsigned char[size]}} or {{c|new (void_ptr) std::byte[size]}} works as an untyped version of {{tt|std::start_lifetime_as}}, but it does not keep the object representation.
 +
 
 +
{{c|std::start_lifetime_as}} handles non-array types as well as arrays of known bound, while {{c|std::start_lifetime_as_array}} handles arrays of unknown bound.
 +
 
 +
{{feature test macro|__cpp_lib_start_lifetime_as|std=C++23|value=202207L|Explicit lifetime management}}
  
 
===Example===
 
===Example===
{{example|code=
+
{{example
 +
|code=
 +
#include <complex>
 +
#include <iostream>
 
#include <memory>
 
#include <memory>
#include <print>
 
#include <utility>
 
  
enum stream_t : unsigned char { FOO, BAR };
+
int main()
struct Foo {
+
{
  stream_t type;
+
    alignas(std::complex<float>) unsigned char network_data[sizeof(std::complex<float>)]
  int data;
+
    {
};
+
        0xcd, 0xcc, 0xcc, 0x3d, 0xcd, 0xcc, 0x4c, 0x3e
struct Bar {
+
    };
  stream_t type;
+
  float data;
+
};
+
  
 +
//  auto d = *reinterpret_cast<std::complex<float>*>(network_data);
 +
//  std::cout << d << '\n'; // UB: network_data does not point to a complex<float>
  
void printFoo(Foo const* ptr) {
+
//  auto d = *std::launder(reinterpret_cast<std::complex<float>*>(network_data));
  std::print("Foo({})", ptr->data);
+
//  std::cout << d << '\n'; // Possible UB, related to CWG1997:
}
+
//      the implicitly created complex<float> may hold indeterminate value
void printBar(Bar const* ptr) {
+
  std::print("Bar({})", ptr->data);
+
}
+
  
void printStream(Stream* stream) {
+
    auto d = *std::start_lifetime_as<std::complex<float>>(network_data);
  // the function read() returns a pointer to an allocated storage
+
     std::cout << d << '\n'; // OK
  // occupied by data bits written by the external stream device.
+
  // and it represents either a Foo or a Bar
+
  std::unique_ptr<unsigned char[]> buffer = stream->read();
+
  if (buffer[0] == std::to_underlying(FOO)) {
+
    // printFoo(reinterpret_cast<Foo*>(buffer.get()));  
+
     // UB. Since the lifetime of the object is not yet started, trying to
+
    // access its data member is undefined behavior.
+
    printFoo(std::start_lifetime_as<Foo>(buffer.get()));
+
    // Ok, since the lifetime are now explicitly started.
+
  } else {
+
    // printBar(reinterpret_cast<Bar*>(buffer.get()));  // UB.
+
    printBar(std::start_lifetime_as<Bar>(buffer.get())); // OK.
+
  }
+
 
}
 
}
 +
|p=true
 
|output=
 
|output=
 +
(0.1,0.2)
 
}}
 
}}
  
=== Notes ===
+
===References===
{{feature test macro|__cpp_lib_start_lifetime_as|std=C++23|value=202207L|Explicit lifetime management}}
+
{{ref std c++23}}
 +
{{ref std|title=Explicit lifetime management|id=obj.lifetime|section=20.2.6}}
 +
{{ref std end}}
  
 
===See also===
 
===See also===
 
{{dsc begin}}
 
{{dsc begin}}
 
{{dsc inc|cpp/numeric/dsc bit_cast}}
 
{{dsc inc|cpp/numeric/dsc bit_cast}}
{{dsc inc|cpp/utility/dsc launder}}
+
{{dsc inc|cpp/container/span/dsc as_bytes}}
 
{{dsc end}}
 
{{dsc end}}
 
===References===
 
{{ref std c++23}}
 
{{ref std|title=Explicit lifetime management|id=obj.lifetime|section=20.2.6}}
 
{{ref std end}}
 
 
  
 
{{langlinks|ar|de|es|fr|it|ja|pl|pt|ru|zh}}
 
{{langlinks|ar|de|es|fr|it|ja|pl|pt|ru|zh}}

Latest revision as of 03:42, 29 August 2024

 
 
Utilities library
General utilities
Relational operators (deprecated in C++20)
 
Dynamic memory management
Uninitialized memory algorithms
Constrained uninitialized memory algorithms
Allocators
Garbage collection support
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)
(C++11)(until C++23)



Explicit lifetime management
start_lifetime_asstart_lifetime_as_array
(C++23)(C++23)

 
Defined in header <memory>
std::start_lifetime_as
template< class T >
T* start_lifetime_as( void* p ) noexcept;
(1) (since C++23)
template< class T >
const T* start_lifetime_as( const void* p ) noexcept;
(2) (since C++23)
template< class T >
volatile T* start_lifetime_as( volatile void* p ) noexcept;
(3) (since C++23)
template< class T >
const volatile T* start_lifetime_as( const volatile void* p ) noexcept;
(4) (since C++23)
std::start_lifetime_as_array
template< class T >
T* start_lifetime_as_array( void* p, std::size_t n ) noexcept;
(5) (since C++23)
template< class T >

const T* start_lifetime_as_array( const void* p,

                                  std::size_t n ) noexcept;
(6) (since C++23)
template< class T >

volatile T* start_lifetime_as_array( volatile void* p,

                                     std::size_t n ) noexcept;
(7) (since C++23)
template< class T >

const volatile T* start_lifetime_as_array( const volatile void* p,

                                           std::size_t n ) noexcept;
(8) (since C++23)
1-4) Implicitly creates a complete object of type T (whose address is p) and objects nested within it. The value of each created object obj of TriviallyCopyable type U is determined in the same manner as for a call to std::bit_cast<U>(E) except that the storage is not actually accessed, where E is the lvalue of type U denoting obj. Otherwise, the values of such created objects are unspecified.
  • [p(char*)p + sizeof(T)) does not denote a region of allocated storage that is a subset of the region of storage reachable through p, or
  • the region is not suitably aligned for the T.
  • Note that the unspecified value can be indeterminate.
5-8) Implicitly creates an array with element type T and length n. To be precise, if n > 0 is true, it is equivalent to std::start_lifetime_as<U>(p) where U is the type "array of n Ts". Otherwise, the function has no effects.
  • T shall be a complete type. Otherwise, the program is ill-formed.
  • The behavior is undefined if:
  • Non-null p is not suitably aligned for an array of T, or
  • n <= std::size_t(-1) / sizeof(T) is false, or
  • n > 0 and [(char*)p(char*)p + (n * sizeof(T))) does not denote a region of allocated storage that is a subset of the region of storage reachable through p.

Contents

[edit] Parameters

p - the address of the region consisting objects
n - the number of the element of the array to be created

[edit] Return value

1-4) A pointer to the complete object as described above.
5-8) A pointer to the first element of the created array, if any; otherwise, a pointer that compares equal to p.

[edit] Notes

new (void_ptr) unsigned char[size] or new (void_ptr) std::byte[size] works as an untyped version of std::start_lifetime_as, but it does not keep the object representation.

std::start_lifetime_as handles non-array types as well as arrays of known bound, while std::start_lifetime_as_array handles arrays of unknown bound.

Feature-test macro Value Std Feature
__cpp_lib_start_lifetime_as 202207L (C++23) Explicit lifetime management

[edit] Example

#include <complex>
#include <iostream>
#include <memory>
 
int main()
{
    alignas(std::complex<float>) unsigned char network_data[sizeof(std::complex<float>)]
    {
        0xcd, 0xcc, 0xcc, 0x3d, 0xcd, 0xcc, 0x4c, 0x3e
    };
 
//  auto d = *reinterpret_cast<std::complex<float>*>(network_data);
//  std::cout << d << '\n'; // UB: network_data does not point to a complex<float>
 
//  auto d = *std::launder(reinterpret_cast<std::complex<float>*>(network_data));
//  std::cout << d << '\n'; // Possible UB, related to CWG1997:
//      the implicitly created complex<float> may hold indeterminate value
 
    auto d = *std::start_lifetime_as<std::complex<float>>(network_data);
    std::cout << d << '\n'; // OK
}

Possible output:

(0.1,0.2)

[edit] References

  • C++23 standard (ISO/IEC 14882:2024):
  • 20.2.6 Explicit lifetime management [obj.lifetime]

[edit] See also

(C++20)
reinterpret the object representation of one type as that of another
(function template) [edit]
converts a span into a view of its underlying bytes
(function template) [edit]