The "undead" clause
I call the undead clause the C++ rule that after the destruction of an object, if a new object is created at the same address, it can sometimes be considered the same object as the old one. That rule always existed in C++ but with some changes on the additional conditions.
I was made to read the latest undead clause by this question. The revised conditions in Lifetime [basic.life]/8 are:
(8.1) the storage for the new object exactly overlays the storage location which the original object occupied, and
Well, duh. An object at a different address would not be the same object.
(8.2) the new object is of the same type as the original object (ignoring the top-level cv-qualifiers), and
Again, duh.
(8.4) neither the original object nor the new object is a potentially-overlapping subobject ([intro.object]).
It cannot a base class, classic (or a member with a special declaration that makes its address not unique). Again, duh.
(8.3) the original object is neither a complete object that is const-qualified nor a subobject of such an object, and
Now that's interesting. The object being replaced can't be either:
- a complete const object
- part of a complete const object
On the other hand, the object being resurrected can be:
- a const member subobject
- a subobject of such const member
- an element in an array of const objects
Const subobject
So it seems to me that all of these objects x
can be resurrected:
Const member subobject
struct CI {
const int x;
};
CI s = { 1 };
new ((void*)&s.x) int(2);
int r = s.x; // OK, 2
Subobject of const member:
struct T {
int x;
};
struct CT {
const T m = { 1 };
};
CT s;
new ((void*)&s.m.x) int (2);
int r = s.m.x;
Element in an array of const objects:
const int x[1] = { 1 };
new ((void*)&x[0]) int (2);
int r = x[0];
Classes with const and reference members
Also object of class type with const or references members do not seem to be prohibited; the resurrected object is still called x
.
Class with a const member:
struct CIM {
CIM(int i): m(i) {}
const int m;
};
CIM x(1);
new ((void*)&x) CIM(2);
int r = x.m; // OK, 2
Class with a reference member:
struct CRM {
CRM (int &r): m(r) {}
int &m;
};
int i=1,j=2;
CRM x(i);
new ((void*)&x) CRM(j);
int r = x.m; // OK, 2
The questions
- Is that interpretation of the clause correct?
- If so, is there any other clause that forbid these overwriting operations?
- If so, is that intended? Why was that changed?
- Is that a breaking change for code generators? Do all compilers really support that? Don't they optimize based on const members, const elements of arrays being immutable and references not being reboundable?
- BONUS QUESTION: does that affect ROM-ability of const objects with adequate storage class (not dynamically created objects, of course) and adequate initialize?
Note: I added the bonus later because putting constants in ROM came up in the discussion.