2

我并不反对下面代码的结果,因为我认为假设 const 左值引用和右值引用都延长了从函数返回的临时值的生命周期是正确的。令我吃惊的是标准中的这一段,似乎与此相反:

12.2p5(强调我的):

第二个上下文是引用绑定到临时的。引用绑定到的临时对象或作为引用绑定到的子对象的完整对象的临时对象在引用的生命周期内持续存在,除了

  • ...
  • ...
  • 临时绑定到函数返回语句 (6.6.3) 中的返回值的生命周期不会延长;临时在 return 语句中的完整表达式的末尾被销毁。

示例代码:

#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';
}
4

2 回答 2

5

您提到的引用专门用于从函数返回引用并将该引用绑定到临时:

const T& f() { return T(); };

在您的代码中不是这种情况,因为您将临时绑定到调用端的引用,而不是在 return 语句中。在您的评论中,您提到当您将代码修改为:

T f() { return T(); }
T&& r = f();

寿命仍然延长,但这是错误的。临时对象在return语句的持续时间内存在,在此期间它被复制到返回值。复制完成后,临时结束的生命周期。在调用方,您有一个不同的临时(的结果f()),其生命周期得到延长。

毫无疑问,临时工的寿命会延长。如果您使用任何消息为类 A 定义析构函数,它将在 main() 的末尾打印,还是在那里?

这种说法也是不正确的。您正在看到返回值优化 (RVO) 的效果。编译器没有为函数内部创建一个临时对象T()并为返回值创建另一个对象,而是在同一位置创建这两个对象。您可能在程序的输出中看到一个对象,但理论上有两个。

您可以尝试将 g++ 与 -fno-elide-constructors 一起使用,您应该能够看到两个临时对象,其中一个已扩展,另一个不会。

或者,您可以返回参考:

const A& f() { return A(); }
const A& r = f();

这应该显示临时死机在r超出范围之前是如何死亡的。


这基本上是相同的测试抑制

$ g++ --版本 | 头-1

g++ (GCC) 4.3.2

$猫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";
}

$ g++ -o t1 x.cpp && ./t1

X
still in main()
~X

$ g++ -fno-elide-constructors -o t2 x.cpp && ./t2

X
~X
still in main()
~X

$ clang++ -版本 | 头-1

$ clang 3.2 版 (tags/RELEASE_32/final)

$ clang++ -fno-elide-constructors -o t3 x.cpp && ./t3

X
~X
still in main()
~X

$猫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";
}

$ g++ -fno-elide-constructors -o t4 y.cpp && ./t4

X
~X
still in main()
于 2013-06-27T22:03:15.503 回答
4

第二个上下文是当一个引用绑定到一个临时的 -除了- 一个临时绑定到函数返回语句中的返回值的生命周期没有被延长

A f() { A a; return a; }

首先,a不是一时的。这可能是你的想法:

A f() { return A(); }

其次,函数的返回类型不是引用类型。以下是该规则适用的时间:

const A& f() { return A(); }

临时 fromA()被绑定到 的返回类型const A&。根据规则,临时的生命周期不会延长。

于 2013-06-27T22:28:11.557 回答