C++ 关于将常量引用绑定到临时对象的子对象
像代码一样C++ 关于将常量引用绑定到临时对象的子对象,c++,language-lawyer,C++,Language Lawyer,像代码一样 #include <stdio.h> struct P2d { double x, y; P2d(double x, double y) : x(x), y(y) {} ~P2d() { printf("Destructor called\n"); } }; P2d center() { return P2d(10, 10); } int main(int argc, const char *argv[]) {
#include <stdio.h>
struct P2d {
double x, y;
P2d(double x, double y) : x(x), y(y) {}
~P2d() { printf("Destructor called\n"); }
};
P2d center() {
return P2d(10, 10);
}
int main(int argc, const char *argv[]) {
const double& x = center().x;
printf("x = %.18g\n", x);
return 0;
}
#包括
结构P2d{
双x,y;
P2d(双x,双y):x(x),y(y){}
~P2d(){printf(“称为析构函数的\n”);}
};
P2d中心(){
返回P2d(10,10);
}
int main(int argc,const char*argv[]{
常数double&x=中心();
printf(“x=%.18g\n”,x);
返回0;
}
g++
(5.2.0版)将在main
中输入printf
之前销毁P2d
临时实例,但该值仍将保留(即,它不会将x
绑定到临时P2d
实例的实际成员,而是创建另一个临时
来复制成员的值)
clang++
(IMO正确地说)相反,将临时P2d
实例的生存期延长到x
引用的生存期,因此在main
中的printf
之后调用析构函数
如果不使用普通的double
作为x
和y
成员的类型,而是创建了一个类(例如double
),则两个编译器都同意,并将临时P2d
对象的生存期延长到printf
之后
这是g++
中的错误还是标准允许的错误?请阅读
这是一个gcc错误。相关规则如下所示: 有两种情况下,临时词语在与完整表达结尾不同的位置被销毁。[…] 第二个上下文是引用绑定到临时对象时。引用绑定到的临时对象或临时对象是引用绑定到的子对象的完整对象 在引用的生命周期内除了:
-在函数调用(5.2.2)中绑定到引用参数的临时对象将一直持续到完成 包含调用的完整表达式的值。
-函数返回语句(6.6.3)中返回值的临时绑定的生存期不是 扩展;在return语句的完整表达式末尾销毁临时表达式。
-与新初始值设定项(5.3.4)中引用的临时绑定持续存在,直到完成 包含新初始值设定项的完整表达式
我们将引用绑定到临时对象的子对象,因此临时对象应在引用的生命周期内保持不变。此规则的三个例外都不适用于此处。我认为g++中存在错误,因为引用§12.2/5: 第二个上下文是当一个引用绑定到一个临时对象时 绑定或作为引用绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在,但以下情况除外: 因此,必须延长其寿命,除非: 临时绑定到构造函数的ctor初始值设定项[…]中的引用成员 临时绑定到函数调用中的引用参数[…] 临时绑定到函数返回语句中返回值的生存期[…] 临时绑定到
新初始值设定项中的引用
我们的案例不适合任何一个例外,因此它必须遵循规则。我认为g++在这里是错误的
然后,关于同一草案§8.5.3/5(重点内容)中提出的aschepler引述:
对类型“cv1T1
”的引用由类型为“cv2T2
”的表达式初始化,如下所示:
如果引用是左值引用和初始值设定项表达式
a、 是左值(但不是位字段),且“cv1T1
”与“cv2T2
”的引用兼容,或
b、 有一个类类型
然后
否则,该引用应为对非易失常数类型的左值引用(即,cv1应为const
),或该引用应为右值引用
a、 如果初始值设定项表达式
- i、 是一个xvalue、类prvalue、数组prvalue或函数左值,“cv1
T1
”是与“cv2T2
”兼容的引用,或
- 有一个班级类型
然后在第一种情况下,引用绑定到初始值设定项表达式的值
b、 否则,将使用非引用副本初始化规则(8.5)从初始值设定项表达式创建并初始化类型为“cv1T1
”的临时副本。然后将引用绑定到临时副本
看看xvalue是什么,这次引用
xvalue(“到期值”)表达式为[…]
a.m
,对象表达式的成员,其中a是右值,m是非引用类型的非静态数据成员
…表达式center().x
应该是一个x值,因此§8.5.3/5中的情况2a适用(并且不是副本)。我将坚持我的建议:g++是错误的。这包括在:
解决问题,并取得会员的成果
应用于prvalue的访问或下标表达式xvalue表示
将引用绑定到临时对象的此类子对象不会
延长临时对象的生存期。12.2[class.temporary]应为
修改以确保它确实如此
目前的现状是——因此(“第二种情况是指引用绑定到临时文件。”)不适用。尽管Clang和GCC并未实际执行第616号问题的决议……我的最佳猜测是:
- GCC根本没有对任何DRs做出反应。