通过rvalue引用返回vs按值返回

时间:2017-09-24 16:43:56

标签: c++ undefined-behavior c++17 rvalue

大多数C ++标准库实用程序在rvalue限定符上重载时返回rvalue引用。例如,std :: optional对value()函数

具有以下重载
constexpr T& value() &;
constexpr const T & value() const &;
constexpr T&& value() &&;
constexpr const T&& value() const &&;

这允许返回值从需要时移动,良好。这是一个可靠的优化。

但是,与右手归来相关的不确定性呢?例如(此处为实例https://wandbox.org/permlink/kUqjfOWWRP6N57eS

auto get_vector() {
    auto vector = std::vector<int>{1, 2, 3};
    return std::optional{std::move(vector)};
}

int main() {
    for (auto ele : *get_vector()) {
        cout << ele << endl;
    }
}

上面的代码会导致未定义的行为,因为基于for循环的范围是如何扩展的

{
    auto && __range = range_expression ; 
    auto __begin = begin_expr ;
    auto __end = end_expr ;
    for ( ; __begin != __end; ++__begin) { 
        range_declaration = *__begin; 
        loop_statement 
    } 
} 

绑定到range的返回值时转发引用*get_vector()不会延长xvalue的生命周期。并导致绑定到破坏的值。因此导致UB。

为什么不按值返回并在内部移动存储的对象?特别是因为现在C ++ 17具有prvalue优化,例如

auto lck = std::lock_guard{mtx};

请注意,这与此问题C++11 rvalues and move semantics confusion (return statement)不同,这并未提及rvalue返回容器/持有者的生命周期扩展问题,并且在C ++ 17强制执行prvalues之前被问到了< / p>

1 个答案:

答案 0 :(得分:5)

  

为什么不按值返回并在内部移动存储的对象?

因为这可能比返回引用效率低。考虑一种情况,您使用返回的引用从该对象中获取另一个引用。例如(*get_vector())[3]。根据您提议的更改,这是对原件副本的引用;它是当前的方式,它是对原始临时值的引用。

C ++作为一种语言并不能有效地处理对临时工具的生命周期。解决方案目前包括要么注意生命周期,要么不使用引用和可能更慢/效率更低的代码。一般而言,标准库更倾向于在性能方面犯错误。