nicolai
nicolai

Reputation: 1222

Does the lifetime of an array object end when its' element storage is reused?

In the subsequent quotes, I'm referring to the ISO standard draft N4713.

§ 6.6.3, paragraph 1 says:

...The lifetime of an object o of type T ends when:
...
— the storage which the object occupies is released, or is reused by an object that is not nested within o (6.6.2).

Please answer the questions in the code comments:

#include <new>

int main() {
    int x[2] = {0, 1};
    char* p = new (x + 1) char{0}; // Has x ended its' lifetime?
    int z = x[0];                  // Is this UB?
}

If I used unsigned char as array element type, the array object x would have provided storage for the *p, according to § 6.6.2, paragraph 3:

If a complete object is created (8.5.2.4) in storage associated with another object e of type “array of N unsigned char” or of type “array of N std::byte” (21.2.1), that array provides storage for the created object if:
— the lifetime of e has begun and not ended, and
— the storage for the new object fits entirely within e, and
— there is no smaller array object that satisfies these constraints.

Please, validate my statements in the code comments:

#include <new>

int main() {
    unsigned char x[2] = {0, 1};
    char* p = new (x + 1) char{0}; // Only x[1] have ended its' lifetime.
    int z = x[0];                  // This is OK.
}

Although I do not understand the last rule in the previous quote, please give an example?

there is no smaller array object that satisfies these constraints.

Upvotes: 4

Views: 419

Answers (1)

Oliv
Oliv

Reputation: 18081

According to the following reading of the standard, the array lifetime is not ended by the placement new expression:

[basic.life]/1.5:

The lifetime of an object o of type T ends when:

  • [...]

  • the storage which the object occupies is released, or is reused by an object that is not nested within o ([intro.object]).

According to this rule, if the new object created within the array is not nested within the array, the array life time end. Otherwise it is not ended.

[intro.object]/2

If an object is created in storage associated with a member subobject or array element e (which may or may not be within its lifetime), the created object is a subobject of e's containing object if:

  • the lifetime of e's containing object has begun and not ended, and

  • the storage for the new object exactly overlays the storage location associated with e, and

  • the new object is of the same type as e (ignoring cv-qualification).

The two last bullets are not full-filled, so obviously, the new char object is not a suboject of the array.

Then [intro.object]/3:

If a complete object is created ([expr.new]) in storage associated with another object e of type “array of N unsigned char” or of type “array of N std​::​byte” ([cstddef.syn]), that array provides storage for the created object if:

  • the lifetime of e has begun and not ended, and

  • the storage for the new object fits entirely within e, and

  • there is no smaller array object that satisfies these constraints.

So the array of unsigned char provides storage for the new char object.

[intro.object]/4:

An object a is nested within another object b if:

  • a is a subobject of b, or

  • b provides storage for a, or

  • there exists an object c where a is nested within c, and c is nested within b.

As we mentioned above, the first bullet is not full-filled. The second one is full-filled. So according to [basic.life]/1.5, the lifetime of the array is not ended because the new char object is nested within the array:

int main() {
    unsigned char x[2] = {0, 1};
    char* p = new (x + 1) char{0}; // x provides storage for the char object
    int z = x[0];                  // OK The first element is within its lifetime.
}

If it were not the case, probably that most of the low-level code would not be standard compliant!

Upvotes: 0

Related Questions