c++ - 复制省略、std::move 和链式函数调用
问题描述
我一直在研究复制省略在没有直接分配给左值并且可能被链接或在路上使用时的行为,但还没有找到任何具体的答案。
对于初学者,我理解NRVO出现在下面的例子中,返回值是直接在destination变量中构造的:
Type MakeType() {
Type type;
// ...
return type;
}
Type a = MakeType();
但是,假设我们有另一个函数接受 Type 作为参数:
Type MakeComplexType(/*some signature*/ param_type) {
Type complex_type = param_type
// ...
return complex_type;
}
我们称之为:
Type t = MakeComplexType(MakeType());
- 是否可以将复制省略一直链接到
t
? - 如果不是,我们是否可以
std::move
策略性地使用,例如在函数调用本身上std::move(MakeType())
,以避免不必要的复制? - 的签名应该是什么才能
param_type
使上述分配t
最有效?
解决方案
复制省略是编译器用来防止不需要的复制的技术。基本上,它在函数外部预先分配内存并将其传递给使用。如果您是临时的,它将在堆栈上。
将 std::move 添加到返回类型没有帮助。您已经按值返回,因此您已经有一个右值。如果我没有操作,使用 std::move 将其转换为没有右值。但是,我不知道细节,在某些情况下添加它会损害性能。
关注 2:在函数调用中添加 std::move 只有在由非常量引用返回时才会产生副作用。在这些情况下,您很可能编写了一个错误,因为原始文件将被移走。
对于数字 3:我最喜欢使用f(Arg &&a)
,因为这要求所有调用者都传递右值。如果性能不太重要,例如:您在分析中没有找到它。值参数(一些调用者可以复制)甚至 const-reference 可能会这样做(函数不能触摸参数,所以应该复制)。
正如评论所指出的,函数的实现也应该写成auto result = std::move(a)
你的参数不能从 NRVO 中受益。
最新版本的 Clang 对何时应使用 std::move 以及何时删除它有很好的警告。我建议启用它们。GCC 可能有一些类似的警告,但我不是最新的。
简而言之:您的原始代码是使用和信任您的编译器的最佳版本,如果它对此有警告。
推荐阅读
- sql - 将全名拆分为 First Middle Last 和 Suffix SQL
- javascript - 如何遍历对象的属性值以验证某些值(也包括对象)的其他特定属性值?
- python - 查找数据集中每个组中的前 3 个项目
- glassfish - Glassfish 6.2.2 CDI 部署失败:null
- ruby - Bundler 已安装但错误提示未安装
- javascript - JavaScript 中的赛车条件
- javascript - Material ui如何在搜索时切换打开的侧边栏
- highcharts - Highcharts 从饼图中隐藏图例项
- python - conda-build 错误:目录“。” 不可安装。未找到“setup.py”和“pyproject.toml”
- python - 使用opencv以特定模式放大图像