在以下代码片段中,return s
给出警告 local variable 's' will be copied despite being returned by name [-Wreturn-std-move]
.为什么会这样?
我使用这个 lambda 函数的目标是获取输入字符串的所有权,然后在通过 RVO 或移动语义修改后返回它。我真的很想避免任何复制。
const auto to_upper = [](std::string&& s) {
std::transform(s.begin(), s.end(), s.begin(),
[](unsigned char c){ return std::toupper(c); }
);
return s;
};
返回 std::move(s)
或 std::forward<std::string>(s)
将解决这个问题,但我认为这没有必要,因为编译器可以省略复制构造函数的使用。另外,我想我应该使用 std::forward
但哪一个是正确的,为什么?
最佳答案
In the following code snippet, the
return s
gives the warninglocal variable 's' will be copied despite being returned by name [-Wreturn-std-move]
. Why is this the case?
那是因为自动推导出函数或 lambda 捕获调用运算符的返回值类型永远不是引用。见 Return type deduction
If the return type does not use
decltype(auto)
, the deduction follows the rules of template argument deduction.
Template argument deduction从不推导出引用。
如果需要引用返回值,则必须明确指定:
const auto to_upper = [](std::string&& s) -> std::string&& {
// ...
return std::move(s);
}
std::move(s)
修复编译器警告,但它不会更改返回值类型,除非明确指定引用返回类型。 An example .编译器警告被破坏。当函数按值返回时,函数参数免于返回值复制省略。
见 copy elision详细信息:
In a
return
statement, when the operand is the name of a non-volatile object with automatic storage duration, which isn't a function parameter or a catch clause parameter, and which is of the same class type (ignoring cv-qualification) as the function return type. This variant of copy elision is known as NRVO, "named return value optimization".
class.copy.elision
:in a
return
statement in a function with a class return type, when the expression is the name of a non-volatile object with automatic storage duration (other than a function parameter or a variable introduced by the exception-declaration of a handler ([except.handle])) with the same type (ignoring cv-qualification) as the function return type, the copy/move operation can be omitted by constructing the object directly into the function call's return object
函数参数和返回值必须同时存在。构造返回值时,局部变量仍然存在,并且可能引用函数参数。只有在构造返回值之后,才会执行局部变量的析构函数。那些析构函数可能会引用函数参数,这就是为什么它的存储不能用于先前构造的返回值的原因。
关于c++ - 尽管按名称返回,为什么仍复制局部变量?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66787397/