Bel*_*loc 2 c++ standards object-lifetime c++11
我不是在反对下面代码的结果,因为我认为假定一个const左值引用和一个右值引用都是正确的,它们都延长了从函数返回的临时值的生命周期.让我感到惊讶的是标准中的这一段,似乎相反:
12.2p5(强调我的):
第二个上下文是引用绑定到临时的.绑定引用的临时对象或绑定引用的子对象的完整对象的临时对象在引用的生命周期内持续存在,除了:
- ...
- ...
- 函数返回语句(6.6.3)中返回值临时绑定的生命周期未扩展; 临时在return语句中的full-expression结束时被销毁.
示例代码:
#include <iostream>
struct A{ A() : i(2) {} int i;};
A f() { A a; return a; }
int main()
{
A&& a1 = f();
std::cout << a1.i << '\n';
const A& a2 = f();
std::cout << a2.i << '\n';
}
Run Code Online (Sandbox Code Playgroud)
您提到的引用专门用于从函数返回引用并绑定对临时引用的引用:
const T& f() { return T(); };
Run Code Online (Sandbox Code Playgroud)
在您的代码中不是这种情况,因为您在调用端将临时绑定到引用,而不是在return语句中.在您的评论中,您提到当您将代码修改为:
T f() { return T(); }
T&& r = f();
Run Code Online (Sandbox Code Playgroud)
寿命仍然延长,但这是错误的.临时生命在return语句的持续时间内,在此期间它被复制到返回的值.复制完成临时结束的生命周期后.在主叫方面,你有一个不同的临时(结果f()),其生命周期得到扩展.
但毫无疑问,临时工的生命延长了.如果为任何消息定义A类的析构函数,它将在main()的末尾打印,或者在那里?
该陈述也是不正确的.您正在看到返回值优化(RVO)的影响.T()编译器在同一位置创建两个对象,而不是为函数内部创建临时函数而为返回值创建另一个临时函数.您可能在程序的输出中看到一个对象,但理论上有两个.
您可以尝试使用带有-fno-elide-constructors的g ++,并且您应该能够看到两个临时值,其中一个是扩展的,另一个不会.
或者,您可以返回参考:
const A& f() { return A(); }
const A& r = f();
Run Code Online (Sandbox Code Playgroud)
哪个应该显示临时死亡如何r超出范围.
这基本上是相同的测试抑制
$ g ++ --version | 头-1
g ++(GCC)4.3.2
$ cat x.cpp
#include <iostream>
struct X {
X() { std::cout << "X\n"; }
~X() { std::cout << "~X\n"; }
};
X f() { return X(); }
int main() {
const X& x = f();
std::cout << "still in main()\n";
}
Run Code Online (Sandbox Code Playgroud)
$ g ++ -o t1 x.cpp && ./t1
X
still in main()
~X
Run Code Online (Sandbox Code Playgroud)
$ g ++ -fno-elide-constructors -o t2 x.cpp && ./t2
X
~X
still in main()
~X
Run Code Online (Sandbox Code Playgroud)
$ clang ++ -version | 头-1
$ clang 3.2版(标签/ RELEASE_32/final)
$ clang ++ -fno-elide-constructors -o t3 x.cpp && ./t3
X
~X
still in main()
~X
Run Code Online (Sandbox Code Playgroud)
$ cat y.cpp
#include <iostream>
struct X {
X() { std::cout << "X\n"; }
~X() { std::cout << "~X\n"; }
};
const X& f() { return X(); }
int main() {
const X& x = f();
std::cout << "still in main()\n";
}
Run Code Online (Sandbox Code Playgroud)
$ g ++ -fno-elide-constructors -o t4 y.cpp && ./t4
X
~X
still in main()
Run Code Online (Sandbox Code Playgroud)