ES.56: Write std::move() only when you need to explicitly move an object to another scope

ES.56:只在需要将一个对象显式移动到另外的作用域时使用std::move

Reason(原因)

We move, rather than copy, to avoid duplication and for improved performance.

我们使用move而不是copy是为了避免不必要的重复并提高性能。

A move typically leaves behind an empty object (C.64), which can be surprising or even dangerous, so we try to avoid moving from lvalues (they might be accessed later).

移动操作一般会留下一个空对象(C.64),它可能引起误解甚至危险。因此我们努力避免移动左值(它们可能在后续代码中被使用)。

Notes(注意)

Moving is done implicitly when the source is an rvalue (e.g., value in a return treatment or a function result), so don't pointlessly complicate code in those cases by writing move explicitly. Instead, write short functions that return values, and both the function's return and the caller's accepting of the return will be optimized naturally.

如果源数据是右值,移动操作会隐式进行(例如return处理或函数的返回值),在这种情况下进行显式移动操作,会导致代码被漫无目标地的复杂化。相反,编写带返回值的简短函数,这样无论是函数的返回值还是调用侧的接受动作都可以很自然地被优化。

In general, following the guidelines in this document (including not making variables' scopes needlessly large, writing short functions that return values, returning local variables) help eliminate most need for explicit std::move.

通常情况下,遵循本文档中的准则(包括不要不必要地扩大变量作用域,编写带返回值的简短函数,返回局部变量等)可以帮助消除显式执行std::move的大部分需求。

Explicit move is needed to explicitly move an object to another scope, notably to pass it to a "sink" function and in the implementations of the move operations themselves (move constructor, move assignment operator) and swap operations.

在显式移动一个对象到另外的作用域时,显式移动是有必要的。特别是:

1.将对象传递给一个“下沉”函数时(接管变量所有权的函数,译者注)

2.实现对象自身移动操作(移动构造函数,移动赋值运算符)和交换操作时

Example, bad(反面示例)

void sink(X&& x);   // sink takes ownership of xvoid user()
{X x;// error: cannot bind an lvalue to a rvalue referencesink(x);// OK: sink takes the contents of x, x must now be assumed to be emptysink(std::move(x));// ...// probably a mistakeuse(x);
}

Usually, a std::move() is used as an argument to a && parameter. And after you do that, assume the object has been moved from (see C.64) and don't read its state again until you first set it to a new value.

通常情况下,std::move()作为为&&参数提供实参。而且在移动之后,应该认为对象已经被移走(参见C.64)并且在赋予新值之前不要获取对象的状态。

void f() {string s1 = "supercalifragilisticexpialidocious";string s2 = s1;             // ok, takes a copyassert(s1 == "supercalifragilisticexpialidocious");  // ok// bad, if you want to keep using s1's valuestring s3 = move(s1);// bad, assert will likely fail, s1 likely changedassert(s1 == "supercalifragilisticexpialidocious");
}

Example(示例)

void sink(unique_ptr<widget> p);  // pass ownership of p to sink()void f() {auto w = make_unique<widget>();// ...sink(std::move(w));               // ok, give to sink()// ...sink(w);    // Error: unique_ptr is carefully designed so that you cannot copy it
}

Notes(注意)

std::move() is a cast to && in disguise; it doesn't itself move anything, but marks a named object as a candidate that can be moved from. The language already knows the common cases where objects can be moved from, especially when returning values from functions, so don't complicate code with redundant std::move()'s.

std::move()实际上是目标为&&的类型转换;它自己不会移动任何东西,而是将命名对象标记为一个移出操作的候选者。语言已经知道对象可以被移出的一般情况,特别是函数的返回值,因此不要因为多余的std::move导致代码复杂化。

Never write std::move() just because you've heard "it's more efficient." In general, don't believe claims of "efficiency" without data (???). In general, don't complicate your code without reason (??). Never write std::move() on a const object, it is silently transformed into a copy (see Item 23 in Meyers15)

永远不要只是因为听说它更高效就使用std::move。通常不要相信那些脱离具体数据的所谓“高效”。通常不要没有理由地让代码复杂化。永远不要对常量对象调用std::move(),这会不知不觉地产生一个拷贝。

Example, bad(反面示例)

vector<int> make_vector() {vector<int> result;// ... load result with datareturn std::move(result);       // bad; just write "return result;"
}

Never write return move(local_variable);, because the language already knows the variable is a move candidate. Writing move in this code won't help, and can actually be detrimental because on some compilers it interferes with RVO (the return value optimization) by creating an additional reference alias to the local variable.

永远不要返回局部变量的移动结果;因为语言已经知道这个变量可以作为移动操作的候选,在这种代码中增加move代码不但没有任何帮助,而且对于某些编译器,由于产生了额外的指向局部变量的引用,增加move代码会影响RVO(返回值优化)的正常执行。

Example, bad(反面示例)

vector<int> v = std::move(make_vector());   // bad; the std::move is entirely redundant

Never write move on a returned value such as x = move(f()); where f returns by value. The language already knows that a returned value is a temporary object that can be moved from.

如果函数f以传值方式返回结果,永远不要对这个返回值调用move操作,例如X=move(f());语言已经知道返回值是临时变量并且可以进行移出操作。

Example(示例)

void mover(X&& x) {call_something(std::move(x));         // okcall_something(std::forward<X>(x));   // bad, don't std::forward an rvalue referencecall_something(x);                    // suspicious, why not std::move?
}template<class T>
void forwarder(T&& t) {call_something(std::move(t));         // bad, don't std::move a forwarding referencecall_something(std::forward<T>(t));   // okcall_something(t);                    // suspicious, why not std::forward?
}

Enforcement(实施建议)

  • Flag use of std::move(x) where x is an rvalue or the language will already treat it as an rvalue, including return std::move(local_variable); and std::move(f()) on a function that returns by value.

  • 标记针对右值或者已经被语言看作是右值的对象调用std::move的情况。包括std::move(local_variable);,std::move(f()),这里函数f是一个以传值方式返回结果的函数。

  • Flag functions taking an S&& parameter if there is no const S& overload to take care of lvalues.

  • 标记没有用于处理左值的const S&型重载函数,只有一个处理右值(参数类型:S&&)的函数的情况。

  • Flag a std::moves argument passed to a parameter, except when the parameter type is an X&& rvalue reference or the type is move-only and the parameter is passed by value.

  • 标记向参数传递std::move执行结果的情况,除非参数类型是右值引用类型X&&,或者参数类型为只移动不拷贝类型并且以传值方式传递。

  • Flag when std::move is applied to a forwarding reference (T&& where T is a template parameter type). Use std::forward instead.

  • 标记对转交引用类型调用std::move的情况(T&&,这里T是模板参数)。

  • Flag when std::move is applied to other than an rvalue reference to non-const. (More general case of the previous rule to cover the non-forwarding cases.)

  • 标记std::move运用于指向非常变量的右值引用以外的情况。(前面规则的更普遍形式,以包含非转交参数的情况)

  • Flag when std::forward is applied to an rvalue reference (X&& where X is a concrete type). Use std::move instead.

  • 标记std::forward用于右值引用的情况(X&&,这里X是具体类型),转而使用std::move。

  • Flag when std::forward is applied to other than a forwarding reference. (More general case of the previous rule to cover the non-moving cases.)

  • 标记std::forward用于转交引用之外的情况。(前面规则的更普遍形式,它可以覆盖非移动参数的情况。)

  • Flag when an object is potentially moved from and the next operation is a const operation; there should first be an intervening non-const operation, ideally assignment, to first reset the object's value.

  • 标记对象可能被执行移出操作而且下一个是常量操作(读取对象值,译者注)的情况;哪里应该首先有一个非常量操作(以便修改对象值,译者注),最好是重新设置对象值的赋值操作。

原文链接

https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#es56-write-stdmove-only-when-you-need-to-explicitly-move-an-object-to-another-scope


新书介绍

以下是本人3月份出版的新书,拜托多多关注!

本书利用Python 的标准GUI 工具包tkinter,通过可执行的示例对23 个设计模式逐个进行说明。这样一方面可以使读者了解真实的软件开发工作中每个设计模式的运用场景和想要解决的问题;另一方面通过对这些问题的解决过程进行说明,让读者明白在编写代码时如何判断使用设计模式的利弊,并合理运用设计模式。

对设计模式感兴趣而且希望随学随用的读者通过本书可以快速跨越从理解到运用的门槛;希望学习Python GUI 编程的读者可以将本书中的示例作为设计和开发的参考;使用Python 语言进行图像分析、数据处理工作的读者可以直接以本书中的示例为基础,迅速构建自己的系统架构。

觉得本文有帮助?欢迎点赞并分享给更多的人。

更新文章,请关注微信公众号【面向对象思考】

C++核心准则ES.56​:只在需要将一个对象显式移动到另外的作用域时使用std::move​相关推荐

  1. C++核心准则ES.40:避免复杂的表达式

    ES.40: Avoid complicated expressions ES.40:避免复杂的表达式 Reason(原因) Complicated expressions are error-pro ...

  2. C++核心准则ES.30: 不要使用宏进行程序中的文本操作​

    ES.30: Don't use macros for program text manipulation ES.30: 不要使用宏进行程序中的文本操作 Reason(原因) Macros are a ...

  3. C++核心准则R.2: 只在接口中表示单独对象使用原始指针​

    R.2: In interfaces, use raw pointers to denote individual objects (only) R.2: 只在接口中表示单独对象使用原始指针 Reas ...

  4. 无符号数的减法_C++核心准则ES.107:不要使用无符号数下标,使用gsl::index更好

    ES.107: Don't use unsigned for subscripts, prefer gsl::index ES.107:不要使用无符号数下标,使用gsl::index更好 Reason ...

  5. switch语句嵌套if_C++核心准则ES.70:进行选择时,switch语句比if语句好

    ES.70: Prefer a switch-statement to an if-statement when there is a choice ES.70:进行选择时,switch语句比if语句 ...

  6. php 语法 条件变量,C ++核心准则:注意条件变量的陷阱

    今天,我写了一篇关于条件变量的恐怖文章.您应该意识到条件变量的这一问题.C ++核心准则CP 42仅声明:"不要无条件等待". 等待!条件变量支持一个非常简单的概念.一个线程准备一 ...

  7. modbus软件开发实战指南_C++核心准则?GSL:指南支持库

    GSL: Guidelines support library GSL:指南支持库 The GSL is a small library of facilities designed to suppo ...

  8. 开源压缩算法brotli_Google的Brotli压缩算法,C ++核心准则以及更多新闻

    开源压缩算法brotli 在本周的开源新闻综述中,我们将介绍Google的Brotli压缩算法,适用于GitHub的Classroom,C ++ Core Guidelines等! 2015年9月20 ...

  9. 使用说明 vector_C++核心准则编译边学-F.20 输出结果时应该使用返回值

    F.20: For "out" output values, prefer return values to output parameters(输出结果时更应该使用返回值而不是输 ...

最新文章

  1. 用 Winetricks 配置 WINE
  2. html load方法的区别,jQuery  中的.load()、$get()、$,post()用法和区别
  3. Communication boosts value
  4. 信息学奥赛一本通(1063:最大跨度值)
  5. 【深度优先搜索】20行代码解决8皇后问题
  6. Android 初级探讨 OOM问题 以及解决优化之道
  7. Vue:router的beforeEach与afterEach钩子函数
  8. html5 excel网页版,一种网页版EXCEL的实现方法与流程
  9. 局部阈值分割法matlab,求matlab图像直方图阈值分割算法(包含预处理步骤)
  10. rmmod不能卸载驱动
  11. Java8 日期时间类
  12. 【室内定位】采用TOA借助多个基站与终端之间距离进行目标定位matlab源码
  13. NPN与PNP的区别与判别
  14. 【十】比例尺添加以及调整
  15. Couldn't figure out the Java version of /root/.jenkins/jdk/bin/java bash: /root/.jenkins/jdk/bin/jav
  16. 关于本地磁盘“介质受写入保护”的解决
  17. Perfectly Secret Encryption
  18. 如何在 Linux下从普通用户切换到root用户
  19. 决策树算法--CART分类树算法
  20. gpu-z怎么用,显卡怎么看体质

热门文章

  1. 跳槽字节跳动,从新手到Flutter架构师,一篇就够!深度好文
  2. AVD的CPU的选择
  3. python数学符号代码_用Python学数学之Sympy代数符
  4. html前端的几种加密/解密方式
  5. 究竟哪些语句是属于DDL?
  6. 字节的UTF-8 序列的字节无效的bug处理方案
  7. android adb修复工具,Android——adb修复build.prop
  8. RISC-V Assembly Programmer's Manual
  9. win设置右键快捷打开软件
  10. 微信小程序获取系统时间、时间戳、时间时间戳加减