Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

std::construct_at to use memory from std::byte / unsigned char arrays

It is a very common example to use std::byte / unsigned char arrays with std::construct_at to provide the storage.

//say A is a NON standard-layout class user-defined class
alignas(A) std::byte storage[sizeof(A)];
std::construct_at(reintrepret_cast<A*>(storage), A{});

However, std::construct_at accepts a pointer to the object, while if you reintrepre_cast a pointer to std::byte / unsigned char array it should still point to the first member of std::byte / unsigned char array. So is the code above illegal? And if so, how to provide a valid pointer to std::construct_at?

like image 530
minex Avatar asked Sep 07 '26 19:09

minex


1 Answers

You seem to be worried that converting between pointers for use in std::construct_at is somehow problematic because you don't have an A object, and perhaps strict aliasing is violated in some way.

Those worries are unnecessary. The code:

std::construct_at(reinterpret_cast<A*>(storage), A{});

... is equivalent to ([expr.reinterpret.cast] p7):

std::construct_at(static_cast<A*>(static_cast<void*>(storage)), A{});

... which is equivalent to ([specialized.construct] p2):

// note: not an exact equivalence, because the std::construct_at version created
//       an additional temporary A{} object
::new (static_cast<void*>(static_cast<A*>(static_cast<void*>(storage)))) A{};

... which is equivalent to ([expr.static.cast] p14):

// note: both the conversion to and from void* leave the pointer value unchanged,
//       so they can be simplified away
// note: an array and its first element have the same address,
//       so we can use both storage and &storage
::new (static_cast<void*>(storage)) A{};

A conversion to void* doesn't require an actual object to exist. There also can't be a strict aliasing violation because you are beginning the lifetime of a new object, not accessing an existing one. Your code is valid.

Other answers in this Q&A mention pointer-interconvertibility, which is not relevant. What matters is the conversion to/from void*, which is a conversion that leaves the pointer value (and thus the address that the pointer represents) unchanged ([conv.ptr] p2). Pointer-interconvertibility would only be relevant to aliasing, and none of this code is performing aliasing.

like image 64
Jan Schultke Avatar answered Sep 11 '26 15:09

Jan Schultke



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!