I want to understand some details about end of lifetime and storage reuse.
I already asked this question about the impact of the reuse "footprint" and got a proper answer for simple objects (TLDR: whatever the footprint of the reuse it ends the lifetime of objects of fundamental types or pointers).
But it naturally extends to objects of compound type such as:
struct A
{
double d;
int i;
double c1;
double d1;
double d2;
};
(A simpler struct could be used to illustrate the question but I'm reusing the one mentioned in another question, see below.)
Another question addresses the case where the object of type A is directly the target of a placement new that ends a subobject lifetime (c1 in the question). As a storage of type A does not provides storage, it is considered as entirely reused, ending the full object lifetime and, also, the lifetime of all the subobjects.
(For the sake of completeness this question covers the similar case where the subobject is explicitly destroyed).
A remaining question is: what happens if the storage is provided by an array of bytes?
#include
#include
#include
struct A {
double d;
int i;
double c1;
double d1;
double d2;
};
int main() {
alignas(A) std::byte storage[sizeof(A)];
std::construct_at(reinterpret_cast(storage), 1., 2, 3., 4., 5.);
// There is a live A object in storage
std::construct_at(
reinterpret_cast(storage + offsetof(A, c1)),
std::uint16_t{0});
// c1 storage is reused, thus ending c1 lifetime: does it ends the A
// object lifetime, does it ends other subobjects lifetimes?
}
Of course, such pattern has no legitimate usage I can think of, but I find it useful to clearly understand the relation between subobjects and objects, regarding lifetime.
Thus the question is, as stated in comments, does ending the lifetime of c1 ends the lifetime of the enclosing object of type A? Does it ends the lifetime of the other subobjects?
So far I only find support in the standard for the following: starting the lifetime of an object only starts the lifetime of its subobjects in some cases (constructor is called, expression new[] for an array,...). Ending the lifetime of an object only ends the lifetime of its subobjects in some cases also (destructor called, delete[] if the enclosing object is an array).
Thus my expectation is that the enclosing object and other subobjects are still in there lifetime but storage + offsetof(A, c1) is not anymore the location of the living double (thus *std::launder(reinterpret_cast would be UB).
I would appreciate standard wording to support or invalidate my claim and to clarify the situation.