全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

详解C++11中的右值引用与移动语义

C++11的一个最主要的特性就是可以移动而非拷贝对象的能力。很多情况都会发生对象的拷贝,有时对象拷贝后就立即销毁,在这些情况下,移动而非拷贝对象会大幅度提升性能。

右值与右值引用

为了支持移动操作,新标准引入了一种新的引用类型——右值引用,就是必须绑定到右值的引用。我们通过&&而不是&来获得右值引用。右值引用一个重要的特性就是只能绑定到将要销毁的对象。

左值和右值是表达式的属性,一些表达式生成或要求左值,而另一些则生成或要求右值。一般而言,一个左值表达式表示的是一个对象的身份,而右值表达式表示的是对象的值。(可以取地址的、有名字的就是左值;不能取地址的、没有名字的就是右值。)两者明显的区别就是左值有持久的状态,而右值要么是字面常量,要么是在表达式求值过程中创建的临时对象。

类似于常规引用(左值引用),一个右值引用也不过是某个对象的另一个名字而已。我们不能将左值引用绑定到要求转换的表达式、字面常量或是返回值的表达式,也不能把右值应用直接绑定到一个左值上。但是,常量左值引用可以绑定到非常量左值、常量左值、右值,是一个万能引用类型。不过相比右值引用所引用的右值,常量左值引用所引用的右值在它的“余生”中只能是只读的。

int i = 42;
int &r = i;     //r引用i
int &r2 = i*2;    //错误,i*2是一个右值
int &&rr = i;    //错误,不能将一个右值引用绑定到一个左值上
int &&rr2 = i*2;   //正确,将rr2绑定到一个乘法结果上
const int &r3 = i*2; //正确,将一个常量引用绑定到一个右值上

变量可以看做只有一个运算对象而没有运算符的表达式,是一个左值。我们不能将一个右值引用直接绑定到一个变量上,即使这个变量是右值引用类型。但是,我们可以通过新标准库中的move函数来获得绑定到左值上的右值引用。

int &&rr3 = std::move(rr2);

注意,被转化的左值,其生命周期并没有随着左右至的转化而改变,在转换之后使用左值可能造成运行时错误。因此,调用move就意味着承诺:除了对原左值变量赋值或销毁它外,我们将不再使用它。不过更多的时候,我们需要转换成右值引用的还是一个确实生命周期即将结束的对象。

移动构造函数和移动赋值运算符

为了让自定义类型也支持移动操作,需要为其定义移动构造函数和移动赋值运算符。这两个成员类似对应的拷贝操作,但它们从给定对象窃取资源而不是拷贝资源。类似于拷贝构造函数,移动构造函数的第一个参数是该类类型的一个右值引用,任何额外的参数都必须有默认实参。除了完成资源移动外,移动构造函数还必须确保移后源对象处于有效的、可析构的状态。

#include <iostream> 
#include <algorithm> 

class MemoryBlock 
{ 
public: 
  // 构造函数
  explicit MemoryBlock(size_t length) : _length(length) , _data(new int[length]) {} 

  // 析构函数 
  ~MemoryBlock() 
  {
    if (_data != nullptr)  delete[] _data;
  } 

  // 拷贝赋值运算符 
  MemoryBlock& operator=(const MemoryBlock& other) 
  { 
    if (this != &other) 
    { 
      delete[] _data; 
      _length = other._length; 
      _data = new int[_length]; 
      std::copy(other._data, other._data + _length, _data); 
    } 
    return *this; 
  } 

  // 拷贝构造函数 
  MemoryBlock(const MemoryBlock& other) 
    : _length(0) 
    , _data(nullptr) 
  { 
    *this = other; 
  } 

  // 移动赋值运算符,通知标准库该构造函数不抛出任何异常(如果抛出异常会怎么样?)
  MemoryBlock& operator=(MemoryBlock&& other) noexcept
  {
    if (this != &other) 
    {  
      delete[] _data; 
      // 移动资源
      _data = other._data; 
      _length = other._length; 
      // 使移后源对象处于可销毁状态
      other._data = nullptr; 
      other._length = 0; 
    } 
    return *this; 
  }

  // 移动构造函数
  MemoryBlock(MemoryBlock&& other) noexcept
    _data(nullptr) 
    , _length(0) 
  { 
    *this = std::move(other); 
  } 

  size_t Length() const 
  { 
    return _length; 
  } 

private: 
  size_t _length; // The length of the resource. 
  int* _data; // The resource. 
};

只有当一个类没有定义任何自己版本的拷贝控制成员,且类的每个非static数据成员都可移动时,编译器才会为它合成移动构造函数会移动赋值运算符。编译器可以移动内置类型;如果一个类类型有对应的移动操作,编译器也能移动这个类型的成员。此外,定义了一个移动构造函数或移动赋值运算符的类必须也定义自己的拷贝操作;否则,这些成员默认地定义为删除的。而移动操作则不同,它永远不会隐式定义为删除的。但如果我们显式地要求编译器生成=defualt的移动操作,且编译器不能移动所有成员,则编译器会将移动操作定义为删除的函数。

如果一个类既有移动构造函数又有拷贝构造函数,编译会使用普通的函数匹配规则来确定使用哪个构造函数。但如果只定义了拷贝操作而未定义移动操作,编译器不会合成移动构造函数,此时即使调用move来移动它们,也是调用的拷贝操作。

class Foo{
public:
  Foo() = default;
  Foo(const Foo&);
  // 为定义移动构造函数
};
Foo x;
Foo y(x);         //调用拷贝构造函数
Foo z(std::move(x));   //调用拷贝构造函数,因为未定义移动构造函数

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


# c++  # 11  # 右值引用  # 移动语义  # 浅析C++11中的右值引用、转移语义和完美转发  # C++11的右值引用的具体使用  # 一文搞懂C++11万能引用和右值引用  # C++11语法之右值引用的示例讲解  # C++ 11新特性之右值引用使用案例与应用场景  # 绑定  # 运算符  # 是一个  # 的是  # 能将  # 而非  # 类似于  # 抛出  # 自己的  # 而不是  # 也不  # 是在  # 第一个  # 也能  # 又有  # 我们可以  # 不过是  # 这两个  # 自定义  # 只有一个 


相关文章: ,巨量百应是干嘛的?  微网站制作教程,不会写代码,不会编程,怎么样建自己的网站?  公司网站的制作公司,企业网站制作基本流程有哪些?  头像制作网站在线制作软件,dw网页背景图像怎么设置?  c# Task.ConfigureAwait(true) 在什么场景下是必须的  如何通过多用户协作模板快速搭建高效企业网站?  香港服务器WordPress建站指南:SEO优化与高效部署策略  如何通过WDCP绑定主域名及创建子域名站点?  杭州银行网站设计制作流程,杭州银行怎么开通认证方式?  图片制作网站免费软件,有没有免费的网站或软件可以将图片批量转为A4大小的pdf?  已有域名如何快速搭建专属网站?  如何通过虚拟主机快速搭建个人网站?  网站制作公司哪里好做,成都网站制作公司哪家做得比较好,更正规?  定制建站如何定义?其核心优势是什么?  高配服务器限时抢购:企业级配置与回收服务一站式优惠方案  矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?  如何破解联通资金短缺导致的基站建设难题?  怀化网站制作公司,怀化新生儿上户网上办理流程?  网站建设设计制作营销公司南阳,如何策划设计和建设网站?  建站之星展会模板:智能建站与自助搭建高效解决方案  如何在云虚拟主机上快速搭建个人网站?  广州网站制作公司哪家好一点,广州欧莱雅百库网络科技有限公司官网?  常州企业网站制作公司,全国继续教育网怎么登录?  如何通过商城免费建站系统源码自定义网站主题?  建站之星如何取消后台验证码生成?  如何在新浪SAE免费搭建个人博客?  红河网站制作公司,红河事业单位身份证如何上传?  建站主机类型有哪些?如何正确选型  宝塔新建站点报错如何解决?  网站按钮制作软件,如何实现网页中按钮的自动点击?  免费制作统计图的网站有哪些,如何看待现如今年轻人买房难的情况?  网站设计制作企业有哪些,抖音官网主页怎么设置?  javascript基本数据类型及类型检测常用方法小结  php json中文编码为null的解决办法  如何规划企业建站流程的关键步骤?  如何在Golang中处理模块冲突_解决依赖版本不兼容问题  广德云建站网站建设方案与建站流程优化指南  小捣蛋自助建站系统:数据分析与安全设置双核驱动网站优化  网站广告牌制作方法,街上的广告牌,横幅,用PS还是其他软件做的?  新网站制作渠道有哪些,跪求一个无线渠道比较强的小说网站,我要发表小说?  建站之星安装路径如何正确选择及配置?  韩国代理服务器如何选?解析IP设置技巧与跨境访问优化指南  建站中国必看指南:CMS建站系统+手机网站搭建核心技巧解析  学生网站制作软件,一个12岁的学生写小说,应该去什么样的网站?  零基础网站服务器架设实战:轻量应用与域名解析配置指南  如何做网站制作流程,*游戏网站怎么搭建?  大同网页,大同瑞慈医院官网?  建站之星如何快速生成多端适配网站?  建站之星ASP如何实现CMS高效搭建与安全管理?  建站主机是否等同于虚拟主机? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。