通过右值引用返回与通过值返回
Returning by rvalue reference vs returning by value
大多数 C++ 标准库实用程序 return 在为此的右值限定符上重载时通过右值引用。例如 std::optional 对 value()
函数
有以下重载
constexpr T& value() &;
constexpr const T & value() const &;
constexpr T&& value() &&;
constexpr const T&& value() const &&;
这允许在需要时移动 returned 值,很好。这是一个可靠的优化。
但是与 returning 右值相关的不确定性呢?例如(现场示例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
}
}
绑定到 *get_vector()
的 return 值时转发引用 range
不会延长 xvalue 的生命周期。并导致绑定到一个被破坏的值。因此导致 UB。
为什么不 return 按值并在内部移动存储的对象?特别是因为现在 C++17 有 prvalue 优化,例如
auto lck = std::lock_guard{mtx};
请注意,这与这里的问题 C++11 rvalues and move semantics confusion (return statement) 不同,这没有提到右值 returns 和 container/holders 的生命周期延长问题,并且在 C 之前被问到++17 对 prvalues
进行了强制省略
Why not return by value and internally move the stored object?
因为这可能比返回引用效率低。考虑这样一种情况,您使用返回的引用从该对象中获取另一个引用。例如 (*get_vector())[3]
。对于您提议的更改,这是对原件副本的引用;目前的方式,它是对原始临时值中的值的引用。
C++ 作为一种语言并不能有效地处理对临时对象的引用的生命周期。目前的解决方案包括要么注意生命周期,要么不使用引用并拥有可能 slower/less 高效的代码。通常,标准库更愿意在性能方面犯错。
大多数 C++ 标准库实用程序 return 在为此的右值限定符上重载时通过右值引用。例如 std::optional 对 value()
函数
constexpr T& value() &;
constexpr const T & value() const &;
constexpr T&& value() &&;
constexpr const T&& value() const &&;
这允许在需要时移动 returned 值,很好。这是一个可靠的优化。
但是与 returning 右值相关的不确定性呢?例如(现场示例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
}
}
绑定到 *get_vector()
的 return 值时转发引用 range
不会延长 xvalue 的生命周期。并导致绑定到一个被破坏的值。因此导致 UB。
为什么不 return 按值并在内部移动存储的对象?特别是因为现在 C++17 有 prvalue 优化,例如
auto lck = std::lock_guard{mtx};
请注意,这与这里的问题 C++11 rvalues and move semantics confusion (return statement) 不同,这没有提到右值 returns 和 container/holders 的生命周期延长问题,并且在 C 之前被问到++17 对 prvalues
进行了强制省略Why not return by value and internally move the stored object?
因为这可能比返回引用效率低。考虑这样一种情况,您使用返回的引用从该对象中获取另一个引用。例如 (*get_vector())[3]
。对于您提议的更改,这是对原件副本的引用;目前的方式,它是对原始临时值中的值的引用。
C++ 作为一种语言并不能有效地处理对临时对象的引用的生命周期。目前的解决方案包括要么注意生命周期,要么不使用引用并拥有可能 slower/less 高效的代码。通常,标准库更愿意在性能方面犯错。