“不死”条款
我将 undead 子句称为 C++ 规则,即在对象销毁后,如果在同一地址创建新对象,则有时可以将其视为与旧对象相同的对象。该规则在 C++ 中始终存在,但附加条件发生了一些变化。
我被迫阅读最新的不死条款这个问题 https://stackoverflow.com/q/59239085/963864。修订后的条件Lifetime [基本生活]/8 https://stackoverflow.com/q/59239085/963864 are:
(8.1) 新对象的存储完全覆盖存储
原始对象占据的位置,以及
嗯,呃。不同地址的对象不会是同一个对象。
(8.2) 新对象与原对象类型相同
(忽略顶级简历限定符),以及
再说一次,呃。
(8.4) 原始对象和新对象都不是
可能重叠的子对象([intro.object])。
它不能是基类、经典类(或具有使其地址不唯一的特殊声明的成员)。再说一次,呃。
(8.3) 原始对象既不是一个完整的对象,
const 限定的也不是此类对象的子对象,并且
现在这很有趣。被替换的对象不能是:
- 一个完整的 const 对象
- 完整 const 对象的一部分
另一方面,被复活的对象可以是:
- const 成员子对象
- 此类常量成员的子对象
- const 对象数组中的元素
常量子对象
所以在我看来所有这些物体x
可以复活:
常量成员子对象
struct CI {
const int x;
};
CI s = { 1 };
new ((void*)&s.x) int(2);
int r = s.x; // OK, 2
const 成员的子对象:
struct T {
int x;
};
struct CT {
const T m = { 1 };
};
CT s;
new ((void*)&s.m.x) int (2);
int r = s.m.x;
const 对象数组中的元素:
const int x[1] = { 1 };
new ((void*)&x[0]) int (2);
int r = x[0];
具有 const 和引用成员的类
此外,具有 const 或引用成员的类类型对象似乎也不被禁止;复活的对象仍然被称为x
.
具有 const 成员的类:
struct CIM {
CIM(int i): m(i) {}
const int m;
};
CIM x(1);
new ((void*)&x) CIM(2);
int r = x.m; // OK, 2
具有参考成员的类:
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
问题
- 该条款的这种解释正确吗?
- 如果是的话,是否还有其他条款禁止这些覆盖操作?
- 如果是这样,这是故意的吗?为什么会改变?
- 这对代码生成器来说是一个重大改变吗?所有编译器真的都支持吗?他们不是基于 const 成员、数组的 const 元素不可变和引用不可反弹来进行优化吗?
- 额外问题:这是否会影响具有足够存储类(当然不是动态创建的对象)和足够初始化的 const 对象的 ROM 能力?
注意:我后来添加了这个奖励,因为在讨论中提到了将常量放入 ROM 中。