C ++标准:按副本返回以初始化没有RVO的引用:是否有任何副本?

时间:2017-06-27 19:08:00

标签: c++ c++14 lifetime rvo

让我们考虑下一个样本:

struct big_type {};

// Return by copy
auto factory() { return big_type{}; }

void any_scope_or_function() {
    big_type&& lifetime_extended = factory();
}

根据假设RVO被禁止或根本不存在,是否会big_type()被复制?或者引用是否直接绑定到return语句中构造的临时值?

我想确保在big_type结束时只调用any_scope_or_function析构函数一次。

我使用C ++ 14,以防某些行为在标准版本之间发生变化。

2 个答案:

答案 0 :(得分:8)

假设在

中没有RVO /拷贝elison
auto factory() { return big_type{}; }

big_type{}将创建一个临时big_type。然后,此对象将用于复制初始化函数返回的对象。这意味着您在函数中创建的对象将被构造和销毁。

使用

big_type&& lifetime_extended = factory();

rvalue引用将延长函数返回的生命周期,因此我们将总共看到一个默认构造函数调用,一个复制/移动构造函数调用和两个析构函数调用。

现在,如果我们改变

auto factory() { return big_type{}; }

big_type factory() { return {}; }

然后我们不再在工厂中创建对象了。使用{}直接初始化return对象,总共给出了一个默认的构造函数调用和一个析构函数调用

答案 1 :(得分:3)

  

或者引用会直接绑定到临时构造的   在退货声明中?

不,它不会。这正是(N)RVO所关注的/你明确地不想要那个。

但是,将尝试使用big_type的移动构造函数,这在技术上不是副本。它确实违反了:“{em> big_type析构函数只在any_scope_or_function结束”时被调用一次,但因为它将被调用两次。

GCC / Clang有一个很好的编译器开关:-fno-elide-constructors,它禁用(N)RVO,可用于将来的参考。目前,here是一个打开该选项的测试,显示双析构函数调用。