I was reviewing a code I proposed to initialize a std::array at compile-time for non-default-constructible objects: https://stackoverflow.com/a/78676552/21691539
in the second version I'm doing:
// creating storage on std::byte to benefit from "implicit object creation"
alignas(alignof(T)) std::byte storage[sizeof(std::array<T, N>)];
std::array<T, N>* const Array =
std::launder(reinterpret_cast<std::array<T, N>*>(storage));
// initializing objects in the storage
T* it =
Array->data(); // construct objects in storage through std::construct_at
for (std::size_t i = 0; i != N; ++i) {
std::construct_at(it, gen(static_cast<int>(i))); // UB?
// new (it) T(gen(static_cast<int>(i))); // not UB?
++it;
}
I wanted to rely on the fact that std::array is an implicit lifetime type but I'm thinking now that I'm UB for the following reason: Array has indeed started its lifetime but none of his subobjects of type T:
Some operations are described as implicitly creating objects within a specified region of storage.[...] [ Note: Such operations do not start the lifetimes of subobjects of such objects that are not themselves of implicit-lifetime types. — end note ]
https://timsong-cpp.github.io/cppwp/n4861/intro.object#10
Does std::construct_at starts this lifetime or just calls the constructor of an object that is already alived inplace (in which case my code would be UB)?
What made me have doubts is the example provided in cppreference that goes through a std::bit_cast to start an object lifetime (thus, AFAIU, in a different memory location than the provided storage).
further research:
std::construct_at:
Effects: Equivalent to: return ::new (voidify(*location)) T(std::forward(args)...);
https://timsong-cpp.github.io/cppwp/n4861/specialized.construct#2
Objects creation 'emphasis mine':
An object is created by a definition, by a new-expression, by an operation that implicitly creates objects (see below), when implicitly changing the active member of a union, or when a temporary object is created.
https://timsong-cpp.github.io/cppwp/n4861/intro.object#1
Linking these two section, is it correct to say that std::construct_at, in fact, actually start an object lifetime at the given location?
std::array<T,N>is an implicit-lifetime type due to class.prop/9, independently of whatTis.