zoukankan      html  css  js  c++  java
  • 右值引用之移动语义

    本文翻译自关于右值引用解释的经典文章,如果英文还可以的话,直接去看英文原文。thbecker.net/articles/rvalue_references/section_01.html

    右值引用是c++中的一个特性,并且已经入驻c++11标准,可能大家一开始接触的时候感觉有点难以理解,但是他的确是很好用的一个玩意儿。

    右值引用解决了两个问题:

    1.move语义 2.完美转发。

    我们接下来先简单介绍一下move语义,但是介绍move语义之前,我们需要先介绍左值和右值的含义。

    在C语言中,我们给出左值的定义为:左值是一个表达式e,那么他既可以出现在赋值操作符的左边,也可以出现在右边。右值是:只允许出现在赋值操作符右边的表达式。

    int a = 42;
    int b = 43;
    
    // a b 都是左值
    a = b; // ok
    b = a; // ok
    a = a * b; // ok
    
    // a * b 是右值
    int c = a * b; // ok, 右值出现在=右边
    a * b = 42; // error, 右值不允许出现在=左边
    

     那么在c++中,左右值的定义也差不多,但是有一点点变化。在c++中,左值是:你可以对它取地址(&)操作的表达式,右值是非左值的表达式。

     // 左值:
      //
      int i = 42;
      i = 43; // ok, i 是左值
      int* p = &i; // ok, i 是左值
      int& foo();
      foo() = 42; // ok, foo() 是左值
      int* p1 = &foo(); // ok, foo() 是左值
    
      // 右值:
      //
      int foobar();
      int j = 0;
      j = foobar(); // ok, foobar() 是右值
      int* p2 = &foobar(); // error, 不能取右值表达式的地址
      j = 42; // ok, 42 是右值

    假设我们有一个类X,他有一个成员函数为一个指针,可能指向某些资源之类的。那么相应的构造、析构、拷贝等操作都是需要一些特殊的处理工作。

    比如我们常见的std::vector,那么X的拷贝操作就类似下面这样:

    X& X::operator=(X const & rhs)
    {
      // [...]
      // 先收回资源m_pResource
      // 对rhs的m_pResource指向的资源做拷贝操作
      // 然后令m_pResource指向新的内存位置.
      // [...]
    }

    或者你可能会遇到下面这种代码:

    X foo();
    X x;
    x = foo();

    那么第三句,也就是最后一句要执行三个操作:

    1.释放原来x的资源。

    2.克隆foo返回值中的资源给x的资源。

    3.销毁释放返回值中的资源。

    很显然,这是很低效的做法,更聪明的做法是swap操作,交换x和返回值x`的资源,然后原x的资源会被自动释放。

    换句话说我们想做的就是:

    ...
    swap(m_pResource,rhs.m_pResource);
    ...

    这个就叫做move语义,在c++11中,通过重载可实现这个特性:

    X& X::operator=(<???> rhs)
    {
      // [...]
      // swap(m_pResource,rhs.m_pResource);
      // [...]  
    }

     那么这个???是个什么类型呢?当然首先它应该是一种引用类型,减少不必要的值拷贝,然后我们还想它和传统的引用类型分开,因为我们希望当右操作数为右值的时候,调用???这个重载,而当右操作数为左值的时候,调用原始的引用赋值构造,那么好吧,那我们就把???叫做“右值引用”好了。

  • 相关阅读:
    基于vue-cli快速构建
    '无法将“vue”项识别为 cmdlet、函数、脚本文件或可运行程序的名称' 或 'vue不是内部或外部命令' 的解决方法
    js / ajax 成功提交后怎么跳转到另外一个页面?
    SpringMVC 拦截器不拦截静态资源的三种处理方式方法
    各种JSON的maven引用
    java版微信公众号支付(H5调微信内置API)
    阿里云MongoDB存储数据
    阿里RocketMq(TCP模式)
    Nginx 简单安装
    Redis-主从复制
  • 原文地址:https://www.cnblogs.com/houhoujun/p/4403802.html
Copyright © 2011-2022 走看看