本文为第四部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/4220233.html

强制Move语义

众所周知,正如C++标准的第一修正案所陈述:“委员会不会建立任何试图绊住C++程序员的脚的规则。(The committee shall make no rule that prevents C++ programmers from shooting themselves in the foot.”,正经来说,就是当面临给予程序员更多控制还是减少他们粗心大意机会的选择时,C++更倾向于及时可能导致犯错,但是依然给予更多控制。正是基于这种精神,C++11允许你使用Move语义而不仅仅局限于是右值,而是还有左值,这都给与你充分的决定权。一个好的例子就是标准库里面的swap方法。同以前一样,给出一个类X,基于它我们可以重载拷贝构造函数和拷贝赋值操作符来在右值上面实现Move语义。

template<class T>
void swap(T& a, T& b)
{
T tmp(a);
a = b;
b = tmp;
} X a, b;
swap(a, b);

这里并没有右值。所以,在swap函数中的三行没有使用move语义。但是我们知道使用move语义是可行的:任何时候当一个变量作为源头出现在一个拷贝构造函数或者赋值语句的时候,那个变量将不会再被使用,或者仅仅被作为赋值的目标。

在C++11中,标准库中有一个叫做std::move的方法用来处理这种情况。这个函数只是将他的参数变成右值。因此,在C++11中,标准库函数swap将会像如下所示:

template<class T>
void swap(T& a, T& b)
{
T tmp(std::move(a));
a = std::move(b);
b = std::move(tmp);
} X a, b;
swap(a, b);

现在所有在swap函数中的三行都使用了move语义。记住对于没有实现move语义的类型(也就是说,并没有为右值单独重载一个拷贝构造函数和赋值表达式的类型),新的swap行为表现同旧的版本是一致的。

std::move是一个非常简单的函数。不幸的是,尽管如此,我还不能将它的实现展现给你。我们将会在后面讨论它。

在任何能使用std::move的地方使用它。如上面的swap函数所示,它给我们带来如下好处:

  • 对于实现了move语义的类型而言,需要标准库算法和操作将会使用move语义,然后因此得到潜在的性能提升。一个重要的例子就是原地排序(inplace sorting):原地排序算法就是单纯的交换元素,其他什么都不做,然后现在交换的过程将会在提供了move语义的类型中,充分利用到move语义提供的优势。
  • 标准模板库(STL)经常需要有些类型提供拷贝能力(copyability)。例如可以被用做容器元素的类型。通过严格的观察,事实证明,在很多情况下,移动能力(moveability)就足够了。因此,我们现在可以在某些以前并不被允许的地方使用可移动的而不是可复制的类型了(譬如unique_pointer)。举例来说,这些类型现在可以被使用做标准模板库的容器类型了。

既然我们知道了std::move,我就就需要知道为什么实现一个基于右值引用的拷贝赋值表达式的重载,如同前面我所展示的,依然是有些问题的。考虑一个简单的变量间的赋值,像这样:

a = b;

你期待在这里发生什么?你期待被a持有的对象被一份b的拷贝所替代,当然在整个交换过程中,你期待原来被a持有的对象会被析构。现在考虑这行代码:

a = std::move(b);

如果move语义被实现为一个简单的交换,那么这里的表现就将会是被a和b持有的对象将在a和b间交换。没有任何东西被析构。当然原来被a持有的对象将会最终被析构,也就是说,当b离开了该代码的范围时。当然,除非b成为move的对象,在这种情况下,原来被a持有的对象又再次得到了一次。因此,只有拷贝赋值表达式的实现被精心考虑过后,我们并不知道原来被a持有的对象何时将被析构。

所以在某种意义上,我们在这里将会陷入到不确定性的泥沼中:一个变量被分配后,但是原来被该变量持有的对象却还在其他位置。只有那个对象的析构函数并不会对外面有任何副作用的时候才是可行的。但是某些时候,析构函数确实会有这种副作用。一个例子就是在析构函数中释放一个锁。因此,析构函数中任何可能含有副作用的部分应该在拷贝赋值操作符的右值引用重载中清晰地表现出来:

X& X::operator=(X&& rhs)
{ // 执行一次清理,要注意到那些在析构函数中可能产生副作用的地方。
// 确保对象处于可析构的和可赋值的状态 // Move语义,交换this和rhs的内容 return *this;
}

翻译「C++ Rvalue References Explained」C++右值引用详解 Part4:强制Move语义的更多相关文章

  1. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part6:Move语义和编译器优化

    本文为第六部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.ht ...

  2. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part1:概述

    本文系对「C++ Rvalue References Explained」 该文的翻译,原文作者:Thomas Becker. 该文较详细的解释了C++11右值引用的作用和出现的意义,也同时被Scot ...

  3. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part8:Perfect Forwarding(完美转发):解决方案

    本文为第八部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.ht ...

  4. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part3:右值引用

    本文为第三部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/4220233.html. 右值引用 如果x是任意类型,那么x&&则被称作一个 ...

  5. 翻译「C++ Rvalue References Explained」C++右值引用详解 Part5:右值引用就是右值吗?

    本文为第五部分,目录请参阅概述部分:http://www.cnblogs.com/harrywong/p/cpp-rvalue-references-explained-introduction.ht ...

  6. 「翻译」Unity中的AssetBundle详解(二)

    为AssetBundles准备资源 使用AssetBundles时,您可以随意将任何Asset分配给所需的任何Bundle.但是,在设置Bundles时,需要考虑一些策略.这些分组策略可以使用到任何你 ...

  7. 「翻译」Unity中的AssetBundle详解(一)

    AssetBundles AssetBundle是一个存档文件,其中包含平台在运行时加载的特定资产(模型,纹理,预制,音频剪辑,甚至整个场景).AssetBundles可以表示彼此之间的依赖关系;例如 ...

  8. C++11标准之右值引用(rvalue reference)

    1.右值引用引入的背景 临时对象的产生和拷贝所带来的效率折损,一直是C++所为人诟病的问题.但是C++标准允许编译器对于临时对象的产生具有完全的自由度,从而发展出了Copy Elision.RVO(包 ...

  9. c++11-17 模板核心知识(十)—— 区分万能引用(universal references)和右值引用

    引子 如何区分 模板参数 const disqualify universal reference auto声明 引子 T&&在代码里并不总是右值引用: void f(Widget&a ...

随机推荐

  1. 安卓 NEXUS6 修改分辨率,density

    NEXUS6原density数值: 2k屏 560 每一步: 使用RE文件管理器,编辑system/build.prop.将“ro.sif.lcd_density=”的参数改写成为需要修改的数值,保存 ...

  2. SPOJ #752. Power it!

    By property of mod operations , we can simply use Divide and Conquer + Recursion to solve it. Refere ...

  3. python命令行下tab键补全命令

    在python命令行下不能使用tab键将命令进行补全,手动输入又很容易出错. 解决:tab.py #/usr/bin/env python # -*- coding:utf-8 -*- ''' 该模块 ...

  4. SSL证书在线工具

    证书在线工具 如果您是第一次申请SSL证书,如果您对您的服务器如何使用SSL证书还不熟悉的话,我们推荐您使用本套工具,本套工具支持所有SSL服务器证书格式和各种WEB服务器.帮助您在线生成CSR文件, ...

  5. 71. Simplify Path

    Given an absolute path for a file (Unix-style), simplify it. For example,path = "/home/", ...

  6. java中用中国网建提供的SMS短信平台发送短信

    接下来的项目需求中提到需要短信发送功能,以前没有做过,因此便在网上搜了一下.大体上说的都是有三种方法,分别是sina提供的webservice接口.短信mao和中国网建提供的SMS短信平台. 这三种方 ...

  7. Service代码示例

    package com.homily.training.service; import android.app.Service; import android.content.Intent; impo ...

  8. git 使用详解(8)-- tag打标签

    打标签 同大多数 VCS 一样,Git 也可以对某一时间点上的版本打上标签.人们在发布某个软件版本(比如 v1.0 等等)的时候,经常这么做.本节我们一起来学习如何列出所有可用的标签,如何新建标签,以 ...

  9. BIP_开发案例07_将原有Report Builer报表全部转为XML Publisher形式(案例)

    2014-05-31 Created By BaoXinjian

  10. Form_Form Builder Export导出为Excel(案例)

    2014-01-09 Created By BaoXinjian