Difference between revisions of "cpp/memory/start lifetime as"
From cppreference.com
(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; | |
}} | }} | ||
{{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; | |
}} | }} | ||
{{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; | |
}} | }} | ||
{{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; | |
}} | }} | ||
− | {{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; | |
}} | }} | ||
{{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, | |
− | + | 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, | |
− | + | 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, | |
− | + | std::size_t n ) noexcept; | |
}} | }} | ||
{{dcl end}} | {{dcl end}} | ||
− | @1-4@ [[cpp/language/object#Object creation| | + | @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 | + | * {{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 {{ | + | :* {{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| | + | @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, | + | * {{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 {{ | + | :* Non-null {{c|p}} is not suitably aligned for an array of {{tt|T}}, or |
− | :* {{c|n < | + | :* {{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 {{ | + | :* {{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 | | + | {{par|p|the address of the region consisting objects}} |
− | {{par | n | | + | {{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 {{ | + | @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> | ||
− | |||
− | |||
− | + | 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 | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
+ | |p=true | ||
|output= | |output= | ||
+ | (0.1,0.2) | ||
}} | }} | ||
− | === | + | ===References=== |
− | {{ | + | {{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/ | + | {{dsc inc|cpp/container/span/dsc as_bytes}} |
{{dsc end}} | {{dsc 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
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, |
(6) | (since C++23) |
template< class T > volatile T* start_lifetime_as_array( volatile void* p, |
(7) | (since C++23) |
template< class T > const volatile T* start_lifetime_as_array( const volatile void* p, |
(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.
-
T
shall be an ImplicitLifetimeType and shall be a complete type. Otherwise, the program is ill-formed. - The behavior is undefined if:
-
[
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 T
s". 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.
- Non-null p is not suitably aligned for an array of
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
Run this code
#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) |
(C++20) |
converts a span into a view of its underlying bytes (function template) |