什么时候应该在函数返回值上使用std :: move? [英] When should std::move be used on a function return value?

查看:334
本文介绍了什么时候应该在函数返回值上使用std :: move?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这种情况下

struct Foo {};
Foo meh() {
  return std::move(Foo());
}



我确定移动是不必要的,因为新创建的<

I'm pretty sure that the move is unnecessary, because the newly created Foo will be an xvalue.

但是在这样的情况下呢?

But what in cases like these?

struct Foo {};
Foo meh() {
  Foo foo;
  //do something, but knowing that foo can safely be disposed of
  //but does the compiler necessarily know it?
  //we may have references/pointers to foo. how could the compiler know?
  return std::move(foo); //so here the move is needed, right?
}

需要移动,我想是吗?

推荐答案

的情况下返回std :: move(foo); move 是多余的,因为12.8 / 32:

In the case of return std::move(foo); the move is superfluous because of 12.8/32:


当满足复制操作的标准或者将
符合保存,因为源对象是函数参数
,并且要复制的对象由lvalue指定,重载
分辨率以选择复制的构造函数

When the criteria for elision of a copy operation are met or would be met save for the fact that the source object is a function parameter, and the object to be copied is designated by an lvalue, overload resolution to select the constructor for the copy is first performed as if the object were designated by an rvalue.

return foo;

return foo; is a case of NRVO, so copy elision is permitted. foo is an lvalue. So the constructor selected for the "copy" from foo to the return value of meh is required to be the move constructor if one exists.

添加 move 确实有潜在的效果,但是:它防止移动被省略,因为 return std :: move(foo); 是不符合NRVO资格。

Adding move does have a potential effect, though: it prevents the move being elided, because return std::move(foo); is not eligible for NRVO.

据我所知,12.8 / 32列出了条件,根据该条件,可以通过移动替换来自左值的副本。一般来说,编译器不允许检测副本后使用左值(使用DFA),并主动进行更改。我假设这里有一个可观察的差异 - 如果可观察的行为是相同的,那么as-if规则适用。

As far as I know, 12.8/32 lays out the only conditions under which a copy from an lvalue can be replaced by a move. The compiler is not permitted in general to detect that an lvalue is unused after the copy (using DFA, say), and make the change on its own initiative. I'm assuming here that there's an observable difference between the two -- if the observable behavior is the same then the "as-if" rule applies.

回答标题中的问题,当你想要移动它时,在返回值上使用 std :: move ,它不会被移动。也就是:

So, to answer the question in the title, use std::move on a return value when you want it to be moved and it would not get moved anyway. That is:


  • 您希望将其移动,

  • 这是一个左值,

  • 它不符合复制elision的条件,

  • 它不是按值函数参数的名称。

  • you want it to be moved, and
  • it is an lvalue, and
  • it is not eligible for copy elision, and
  • it is not the name of a by-value function parameter.

考虑到这是非常繁琐,移动通常很便宜,你可能想说在非模板代码中,你可以简化这有点。在以下情况下使用 std :: move

Considering that this is quite fiddly and moves are usually cheap, you might like to say that in non-template code you can simplify this a bit. Use std::move when:



  • 这是一个左值,

  • 您不能担心它。

按照简化的规则,你牺牲了一些移动精度。对于类似 std :: vector 这是便宜的移动你可能永远不会注意到(如果你注意到你可以优化)。对于像移动昂贵的 std :: array 类型,或者你不知道移动是否便宜的模板,你更可能会担心关于它。

By following the simplified rules you sacrifice some move elision. For types like std::vector that are cheap to move you'll probably never notice (and if you do notice you can optimize). For types like std::array that are expensive to move, or for templates where you have no idea whether moves are cheap or not, you're more likely to be bothered worrying about it.

这篇关于什么时候应该在函数返回值上使用std :: move?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆