c++ - 尽管按名称返回,为什么局部变量被复制?
问题描述
在下面的代码片段中,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)
orstd::forward<std::string>(s)
将解决问题,但我认为这不是必需的,因为编译器可以省略复制构造函数的使用。另外,我认为我应该使用std::forward
,但哪一个是正确的,为什么?
解决方案
在下面的代码片段中,
return s
给出了警告local variable 's' will be copied despite being returned by name [-Wreturn-std-move]
。为什么会这样?
这是因为自动推导出函数的返回值类型或 lambda 捕获调用运算符永远不是引用。见退货类型扣除
如果返回类型不使用
decltype(auto)
,则推演遵循模板实参推演规则。
模板参数推导从不推导引用。
如果需要引用返回值,则必须明确指定:
const auto to_upper = [](std::string&& s) -> std::string&& {
// ...
return std::move(s);
}
std::move(s)
修复编译器警告,但不会更改返回值类型,除非明确指定引用返回类型。一个例子。编译器警告已损坏。
当函数按值返回时,函数参数不受返回值复制省略的影响。
有关完整详细信息,请参阅复制省略:
在
return
语句中,当操作数是具有自动存储持续时间的非易失性对象的名称时,该对象不是函数参数或 catch 子句参数,并且与函数返回类型。这种复制省略的变体被称为 NRVO,“命名返回值优化”。
在
return
具有类返回类型的函数的语句中,当表达式是具有自动存储持续时间的非易失性对象的名称时(除了函数参数或由处理程序的异常声明引入的变量([except. handle]) ) 与函数返回类型相同类型(忽略 cv 限定),可以通过将对象直接构造到函数调用的返回对象中来省略复制/移动操作
函数参数和返回值必须同时共存。构造返回值时,局部变量仍然存在,可以引用函数参数。只有在构造了返回值之后,才会执行局部变量的析构函数。那些析构函数可能会引用函数参数,这就是为什么它的存储不能被重用于之前构造的返回值。
推荐阅读
- java - 在android中比较两个字符串,如url
- netlogo - Netlogo:计算自己和其他代理之间的距离
- google-apps-script - 试图从工作表中的不同选项卡获取 url
- jquery - 在移动设备上强制 jPlayer 缓冲条
- c# - PHP的openssl_sign在C#中使用字符串
- vb.net - InternetMessageHeaders 不更新 EWS
- apache - 设置 puppet 并安装 apache 包问题
- android - 无法解决:构建 gradle 后 com.android.support 但我的应用仍然可以安装
- python-3.x - Python3 运行带有多个预期引号的复杂 shell 命令
- java - 网络摄像头捕获 - 请求图像时超时