1

Is the static memory section alignas(alignof(T)) char bytes[sizeof(T)] suitable to hold an instance of T during its lifetime by calling std::construct_at(bytes, ...) / std::destroy_at(bytes)? My instincts say, yeah, the alignment and size requirements are guaranteed, so after construction (since there are also trivially constructible types, I prefer to call it initialization) reinterpret_cast<T*>(bytes) is a valid pointer to a completely valid instance of type T.

Am I missing something?

PS: I could also write std::aligned_storage_t<sizeof(T), alignof(T)> bytes - in that case its memory would be referenced as &bytes or std::addressof(bytes).

plasmacel
  • 8,183
  • 7
  • 53
  • 101

1 Answers1

3

Is the static memory section alignas(alignof(T)) char bytes[sizeof(T)] suitable to hold an instance of T during its lifetime by calling std::construct_at(bytes, ...) / std::destroy_at(bytes)?

Yes.

reinterpret_cast<T*>(bytes) is a valid pointer to a completely valid instance of type T.

Am I missing something?

You would still need to launder a pointer to reused memory:

T* ptr1 = std::construct_at(reinterpret_cast<T*>(bytes), ...); // valid
T* ptr2 = std::launder(reinterpret_cast<T*>(bytes)); // valid
std::destroy_at(ptr2); // valid, just like std::destroy_at(ptr1)
plasmacel
  • 8,183
  • 7
  • 53
  • 101
eerorika
  • 232,697
  • 12
  • 197
  • 326
  • Good catch! `std::launder` always was something obscure to me, even since it didn't exist before C++17 where we simply did a `reinterpret_cast`. – plasmacel Aug 02 '21 at 11:01
  • 1
    @plasmacel Yeah, before then we just had to play with UB, or always only use the pointer returned by placement new. – eerorika Aug 02 '21 at 11:03
  • Should I also launder the pointer which is passed to `std::destroy_at`? Like `std::destroy_at(std::launder(reinterpret_cast(bytes)));`. – plasmacel Aug 02 '21 at 12:08
  • 1
    @plasmacel Yes, you have to always launder when getting the pointer from `bytes`. – eerorika Aug 02 '21 at 12:12
  • Note that `std::construct_at` takes a pointer type `T*`, where `T` is the type you want to make an instance of. So it is actually `std::construct_at(std::launder(reinterpret_cast(bytes)), ...)`. – plasmacel Aug 02 '21 at 13:04
  • @plasmacel Yup. Good catch. I don't think laundering is needed there since `std::construct_at` won't indirect through the pointer. But it won't hurt either. – eerorika Aug 02 '21 at 13:07