问题描述
我将undead子句称为C ++规则,即销毁对象后,如果在同一地址创建一个新对象,则有时可以将其视为与旧对象相同的对象.该规则始终存在于C ++中,但在附加条件上有所更改.
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.
这个问题使我阅读了最新的不死条款. 生命周期中的修订条件为:
[basic.life]/8 :
I was made to read the latest undead clause by this question. The revised conditions in Lifetime [basic.life]/8 are:
嗯,嗯.位于不同地址的对象将不是同一对象.
Well, duh. An object at a different address would not be the same object.
再次,du.
它不能是经典的基类(或具有特殊声明使其地址不唯一的成员).再次,嗯.
It cannot a base class, classic (or a member with a special declaration that makes its address not unique). Again, duh.
现在很有趣.被替换的对象不能是:
Now that's interesting. The object being replaced can't be either:
- 完整的const对象
- 完整的const对象的一部分
另一方面,要复活的对象可以是:
On the other hand, the object being resurrected can be:
- 一个const成员子对象
- 此类const成员的子对象
- 一个const对象数组中的元素
const子对象
所以在我看来,所有这些对象x
都可以复活:
const成员子对象
Const member subobject
struct CI {
const int x;
};
CI s = { 1 };
new ((void*)&s.x) int(2);
int r = s.x; // OK, 2
const成员的子对象:
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;
一个const对象数组中的元素:
Element in an array of const objects:
const int x[1] = { 1 };
new ((void*)&x[0]) int (2);
int r = x[0];
具有const和引用成员的类
似乎也不禁止带有const或引用成员的类类型的对象;恢复的对象仍称为x
.
具有const成员的类:
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
带有参考成员的课程:
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的情况.
Note: I added the bonus later because putting constants in ROM came up in the discussion.
推荐答案
如果与对象生存期相关的标准的所有要求都不在[basic-life]中,那将是令人惊讶的.
It would be surprising if all requirement of the standard related to object life-time were not in [basic-life].
在您引用的标准段落中,很少有将完整"形容词无意中添加到名称对象"的情况.
There are few chances that the "complete" adjective has been inadvertedly added to the name "object" in the standard paragraph you cite.
在论文 P0137 中,人们可以读懂这一道理(在下面的@LanguageLawyer评论中引用的论文):
In the paper P0137, one can read this rational (paper cited in @LanguageLawyer comment below):
为了使我们放心,我们可以验证编译器确实遵循字母的标准措辞:它们对完整的const对象执行常量优化,但对非const完整对象的const成员对象不执行常量优化:
To reassure us, we can verify that compilers do follow the standard wording at the letter: they perform constant optimization for complete const objects but not for const member suboject of non const complete objects:
让我们考虑此代码:
struct A{const int m;};
void f(const int& a);
auto g(){
const int x=12;
f(x);
return x;
}
auto h(){
A a{12};
f(a.m);
return a.m;
}
在将x86_64作为目标时,Clang和GCC都会生成此程序集:
Both Clang and GCC generates this assembly when targeting x86_64:
g(): # @g()
push rax
mov dword ptr [rsp + 4], 12
lea rdi, [rsp + 4]
call f(int const&)
mov eax, 12 ;//the return cannot be anything else than 12
pop rcx
ret
h(): # @h()
push rax
mov dword ptr [rsp], 12
mov rdi, rsp
call f(int const&)
mov eax, dword ptr [rsp] //the content of a.m is returned
pop rcx
ret
返回的值放在寄存器eax
中(根据ABI规范:System V x86处理器特定的ABI):
The returned value is placed in register eax
(according to the ABI specification: System V x86 processor specific ABI):
-
在函数
g
中,编译器可以自由假定不能在调用f
的过程中更改x
,因为x
是完整的const对象.因此,值12
作为直接值直接放置在eax
寄存器中:mov eax, 12
.
In the function
g
the compiler is free to suppose thatx
can not be changed accross the call tof
becausex
is a complete const object. So the value12
is placed directly in theeax
register as an immediate value:mov eax, 12
.
在函数h
中,编译器不能随意假设不能在调用f
的过程中更改a.m
,因为a.m
不是完整const对象的子对象.因此,在调用f
之后,必须将a.m
的值从内存加载到eax
:mov eax, dword ptr [rsp]
.
In the function h
the compiler is not free to suppose that a.m
can not be changed accross the call to f
because a.m
is not a suboject of a complete const object. So after the call to f
the value of a.m
must be loaded from memory to eax
: mov eax, dword ptr [rsp]
.
这篇关于亡灵对象([basic.life]/8):为什么允许引用重新绑定(和const修改)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!