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.
const
complete objects at all. Since it only makes sense to put complete objects in ROM and they can only be placed there if the complete object isconst
, there is no issue with that here. – Manxmanint64_t
in one function and read an IEEEdouble
in another function, even if they are in the same TU, if you went through the ABI by calling a separately compiled function. – Olericulturememcpy
any object even polymorphic (w/o virtual base); on code using GCC class representation: you can copy any object withmemcpy
even one w/ a virtual base. It isn't C++ legal but it's ABI legal. Once you cross the ABI boundary, nobody knows what you did. What happens in Vegas stays in Vegas (it's forgotten) and what happens in a separate compiled module is forgotten. The gains and loss in Vegas are kept and so is the state of all objects in memory. – Olericulture