C++ 标准:return 通过复制来初始化没有 RVO 的引用:有没有复制?

C++ standard: return by copy to initialize a reference without RVO: is there any copy?

让我们考虑下一个示例:

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,以防某些行为在标准版本之间发生变化。

假设没有 RVO/copy elison 那么

auto factory() { return big_type{}; }

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

big_type&& lifetime_extended = factory();

右值引用将延长函数的生命周期 return 因此我们将总共看到一个默认构造函数调用、一个 copy/move 构造函数调用和两个析构函数调用。

现在,如果我们改变

auto factory() { return big_type{}; }

big_type factory() { return {}; }

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

Or will the reference be directly bound to the temporary constructed within the return statement?

不,不会。这正是 (N)RVO about/for 而你明确不想要的。

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

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