C++ - 使用 const 引用来延长临时成员,ok 还是 UB?
C++ - using const reference to prolong a member of a temporary, ok or UB?
考虑这样的事情:
#include <iostream>
struct C {
C(double x=0, double y=0): x(x) , y(y) {
std::cout << "C ctor " << x << " " <<y << " " << "\n";
}
double x, y;
};
struct B {
B(double x=0, double y=0): x(x), y(y) {}
double x, y;
};
struct A {
B b[12];
A() {
b[2] = B(2.5, 14);
b[4] = B(56.32,11.99);
}
};
int main() {
const B& b = A().b[4];
C c(b.x, b.y);
}
当我用 -O0 编译时,我得到打印
C ctor 56.32 11.99
但是当我用 -O2 编译时我得到
C ctor 0 0
我知道我们可以使用 const 引用来延长本地临时文件,所以像
const A& a = A();
const B& b = a.b;
完全合法。但我正在努力寻找为什么相同 mechanism/rule 不适用于任何类型的临时
的原因
编辑以供将来参考:
我使用的是 gcc 版本 6.3.0
A().b[4]
不是临时变量或 rvalue,这就是它不起作用的原因。虽然 A()
是临时的,但您正在创建对创建时存在的数组元素的引用。然后 dtor 触发 A()
,这意味着稍后对 b.b
的访问变得有点不确定。您需要保留 A&
以确保 b
仍然有效。
const A& a = A();
const B& b = a.b[4];
C c(b.x, b.y);
您的代码应该格式正确,因为 temporaries
(强调我的)
Whenever a reference is bound to a temporary or to a subobject thereof, the lifetime of the temporary is extended to match the lifetime of the reference
给定A().b[4]
,b[4]
是b
的子对象,数据成员b
是temprorayA()
的子对象,其生命周期应该被延长。
LIVE on clang10 with -O2
LIVE on gcc10 with -O2
顺便说一句:这似乎是 gcc 的 bug,它已被修复。
根据标准,[class.temporary]/6
The third context is when a reference is bound to a temporary object.36 The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference if the glvalue to which the reference is bound was obtained through one of the following:
...
[ Example:
template<typename T> using id = T;
int i = 1;
int&& a = id<int[3]>{1, 2, 3}[i]; // temporary array has same lifetime as a
const int& b = static_cast<const int&>(0); // temporary int has same lifetime as b
int&& c = cond ? id<int[3]>{1, 2, 3}[i] : static_cast<int&&>(0);
// exactly one of the two temporaries is lifetime-extended
— end example ]
考虑这样的事情:
#include <iostream>
struct C {
C(double x=0, double y=0): x(x) , y(y) {
std::cout << "C ctor " << x << " " <<y << " " << "\n";
}
double x, y;
};
struct B {
B(double x=0, double y=0): x(x), y(y) {}
double x, y;
};
struct A {
B b[12];
A() {
b[2] = B(2.5, 14);
b[4] = B(56.32,11.99);
}
};
int main() {
const B& b = A().b[4];
C c(b.x, b.y);
}
当我用 -O0 编译时,我得到打印
C ctor 56.32 11.99
但是当我用 -O2 编译时我得到
C ctor 0 0
我知道我们可以使用 const 引用来延长本地临时文件,所以像
const A& a = A();
const B& b = a.b;
完全合法。但我正在努力寻找为什么相同 mechanism/rule 不适用于任何类型的临时
的原因编辑以供将来参考:
我使用的是 gcc 版本 6.3.0
A().b[4]
不是临时变量或 rvalue,这就是它不起作用的原因。虽然 A()
是临时的,但您正在创建对创建时存在的数组元素的引用。然后 dtor 触发 A()
,这意味着稍后对 b.b
的访问变得有点不确定。您需要保留 A&
以确保 b
仍然有效。
const A& a = A();
const B& b = a.b[4];
C c(b.x, b.y);
您的代码应该格式正确,因为 temporaries
(强调我的)
Whenever a reference is bound to a temporary or to a subobject thereof, the lifetime of the temporary is extended to match the lifetime of the reference
给定A().b[4]
,b[4]
是b
的子对象,数据成员b
是temprorayA()
的子对象,其生命周期应该被延长。
LIVE on clang10 with -O2
LIVE on gcc10 with -O2
顺便说一句:这似乎是 gcc 的 bug,它已被修复。
根据标准,[class.temporary]/6
The third context is when a reference is bound to a temporary object.36 The temporary object to which the reference is bound or the temporary object that is the complete object of a subobject to which the reference is bound persists for the lifetime of the reference if the glvalue to which the reference is bound was obtained through one of the following:
...
[ Example:
template<typename T> using id = T; int i = 1; int&& a = id<int[3]>{1, 2, 3}[i]; // temporary array has same lifetime as a const int& b = static_cast<const int&>(0); // temporary int has same lifetime as b int&& c = cond ? id<int[3]>{1, 2, 3}[i] : static_cast<int&&>(0); // exactly one of the two temporaries is lifetime-extended
— end example ]