Reputation: 1222
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
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