简体   繁体   English

复制省略,std :: move和链接的函数调用

[英]Copy elision, std::move, and chained function calls

I've been investigating how copy elision behaves when it is not directly assigned to an lvalue and perhaps chained or used down the road, but haven't found any concrete answers. 我一直在研究当复制省略没有直接分配给左值并且可能被链接或沿途使用时如何表现,但是还没有找到任何具体的答案。

For starters, I understand that NRVO occurs in the following example, and the return value is directly constructed in the destination variable: 对于初学者,我理解在以下示例中会发生NRVO,并且直接在目标变量中构造返回值:

Type MakeType() {
  Type type;
  // ...
  return type;
}

Type a = MakeType();

However, let's say we have another function which takes in a Type as a parameter: 但是,假设我们有另一个函数将Type作为参数:

Type MakeComplexType(/*some signature*/ param_type) {
  Type complex_type = param_type
  // ...
  return complex_type;
}

And we call this as follows: 我们称其为:

Type t = MakeComplexType(MakeType());
  1. Is it possible to chain copy elision all the way to t ? 是否可以将复制省略一直链接到t
  2. If not, can we use std::move strategically, perhaps on a function call itself like std::move(MakeType()) , to avoid unnecessary copying? 如果不是,我们是否可以策略性地使用std::move ,也许可以像std::move(MakeType())这样的函数调用本身,以避免不必要的复制?
  3. What should the signature of param_type be such that the above assignment to t is the most efficient? param_type的签名应该是什么才能使上param_type t赋值最有效?

Copy elision is the technique the compiler uses to prevent unneeded copies. 复制省略是编译器用来防止不必要的复制的技术。 Basically, it preallocates memory outside of the function and passes it in to be used. 基本上,它在函数外部预分配内存,并将其传递给使用。 In case of your temporary, it will be on the stack. 如果是临时的,它将放在堆栈中。

Adding std::move to the return type doesn't help. 将std :: move添加到返回类型没有帮助。 You are already returning by value, so you have already an rvalue. 您已经按值返回,因此您已经有一个右值。 Casting it no an rvalue with std::move should me a no-op. 我不应该使用std :: move强制将其强制转换。 I'm not aware of the details, however, for some cases adding it can hurt performance. 我不清楚细节,但是在某些情况下添加它会影响性能。

Focusing on 2: Adding std::move to the function call only has a side effect when returned by non-const reference. 专注于2:将std :: move添加到函数调用仅在由非const引用返回时具有副作用。 In those cases, you most likely wrote a bug as the original will be moved away. 在这些情况下,您很可能写了一个错误,因为原件将被移走。

For number 3: My favorite is using f(Arg &&a) , as this requires all callers to pass rvalue. 对于数字3:我最喜欢的是使用f(Arg &&a) ,因为这要求所有调用方都传递rvalue。 If performance is less important, for example: you did not find it in profiling. 例如,如果性能不太重要:您在性能分析中找不到它。 A value argument (some callers can copy) or even const-reference might do (function can't touch argument, so should copy). 值参数(某些调用者可以复制)甚至const-reference都可以(函数不能触摸参数,因此应该复制)。

As indicated by the comments, the implementation of the function should also write auto result = std::move(a) as your parameter doesn't benefits from NRVO. 如注释所示,该函数的实现还应写入auto result = std::move(a)因为您的参数不会从NRVO中受益。

Recent versions of Clang have very good warnings about when std::move should be used and when to remove it. 最新版本的Clang关于何时应使用std :: move以及何时将其删除的警告非常好。 I suggest enabling them. 我建议启用它们。 GCC might have some similar warnings, however I'm not up to date with it. GCC可能有一些类似的警告,但是我不是最新的。

In short: your original code is the best version to use and trust your compiler if it has warnings about this. 简而言之:如果原始代码有警告,则是使用和信任编译器的最佳版本。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM