IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 右值引用-移动构造详解 -> 正文阅读

[C++知识库]右值引用-移动构造详解

先理解右值引用,要理解右值引用先要回顾左值引用,要理解左值引用先回顾下右值和左值

定义:左值与右值的定义在于一个赋值等号,赋值等号左边成为左值,等号右边成为右值

左值(L-value):表示存储在计算机内存的对象,可寻址,相当于地址值

右值(R-value):代表的为真实值,可读,即数据值

左值引用,是一种数据类型,他是对一个左值的引用,同理右值引用,也是一种数据类型,他是对优质的引用

左值引用常用的场景是函数参数的传递,相当于扩展了左值的作用域到函数中

那么在来说说右值引用,普通的右值引用好理解,下面说下将亡值,C++11中即将消失的变量,如函数的返回值为将亡值,注意将亡值是即将被回收的值,是不能用左值引用的,但是可以进行右值引用,有什么用呢,原来的时候,函数返回,返回值会被拷贝到一个左值中,然后返回值被析构,使用右值引用时候,返回值将不会被析构,直接被右值引用接管,如果返回是是复杂数据类型,就能避免不必要的拷贝构造,提高效率

void fun(int &tmp)
{
    std::cout << tmp << std::endl;
}

int fun1()
{
    int a = 1;
    return a;
}

int main(int argc, char *argv[])
{
    int b = 1; // 左值
    int &rb = b; // 左值引用

    int &&c = 2;  // 右值引用

    int &d = fun1(); // 错误,不能左值引用将亡值
    int &&e = fun1(); // 正确,右值引用将亡值,接管了将亡值,详单与扩展将亡值的作用域


    fun(b);  // 将b的范围扩展到fun函数中
    return 0;
}

下面来说说移动构造,移动构造可以理解为文件的剪切操作,或者理解为二手交易,比如一个人要挂掉了,临走时,他要将自己的东西交付给其他人,之前的做法是通过拷贝构造进行拷贝,然后自己析构挂掉,但移动构造是直接将自己的东西转交给下个人,自己挂掉

原来类有四大默认构造函数、析构函数、拷贝构造函数、赋值函数(operator=),C++11又新增了两个移动构造、移动赋值。

#include <iostream>
#include <algorithm>

class MemoryBlock
{
public:

   // 构造函数
   explicit MemoryBlock(size_t length)
      : _length(length)
      , _data(new int[length])
   {
      std::cout << "gouzao. length = "
                << _length << "." << std::endl;
   }

   // 析构函数.
   ~MemoryBlock()
   {
      std::cout << "xigou. length = "
                << _length << ".";

      if (_data != nullptr)
      {
         std::cout << " Deleting resource.";
         // Delete the resource.
         delete[] _data;
      }

      std::cout << std::endl;
   }

   // 拷贝构造
   MemoryBlock(const MemoryBlock& other)
      : _length(other._length)
      , _data(new int[other._length])
   {
      std::cout << "kaobeigouzao. length = "
                << other._length << ". Copying resource." << std::endl;

      std::copy(other._data, other._data + _length, _data);
   }

   // 拷贝赋值函数.
   MemoryBlock& operator=(const MemoryBlock& other)
   {
      std::cout << "keobeifuzhi. length = "
                << other._length << ". Copying resource." << std::endl;

      if (this != &other)
      {
         // Free the existing resource.
         delete[] _data;

         _length = other._length;
         _data = new int[_length];
         std::copy(other._data, other._data + _length, _data);
      }
      return *this;
   }

   // 移动构造
   MemoryBlock(MemoryBlock&& other) noexcept
      : _data(nullptr)
      , _length(0)
   {
      std::cout << "yidonggouzao. length = "
                << other._length << ". Moving resource." << std::endl;

      // Copy the data pointer and its length from the
      // source object.
      _data = other._data;
      _length = other._length;

      // Release the data pointer from the source object so that
      // the destructor does not free the memory multiple times.
      other._data = nullptr;
      other._length = 0;
   }

   // 移动赋值.
   MemoryBlock& operator=(MemoryBlock&& other) noexcept
   {
      std::cout << "yidongfuzhi. length = "
                << other._length << "." << std::endl;

      if (this != &other)
      {
         // Free the existing resource.
         delete[] _data;

         // Copy the data pointer and its length from the
         // source object.
         _data = other._data;
         _length = other._length;

         // Release the data pointer from the source object so that
         // the destructor does not free the memory multiple times.
         other._data = nullptr;
         other._length = 0;
      }
      return *this;
   }

   // Retrieves the length of the data resource.
   size_t Length() const
   {
      return _length;
   }

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

MemoryBlock getMemoryBlock()
{
    return MemoryBlock(5);
}

// 注意:     该例子需要需要关闭编译其优化选项QMAKE_CXXFLAGS += -fno-elide-constructors

int main(int argc, char *argv[])
{
    MemoryBlock m(2);    // 调用构造
    MemoryBlock n(m); // 调用拷贝构造
    MemoryBlock n1 = m; // 调用拷贝构造
    MemoryBlock n2(3);
    n2 = m; // 调用拷贝赋值

    //MemoryBlock &tmp = getMemoryBlock();  // 错误,不能左值引用将亡值
    MemoryBlock &&tmp = getMemoryBlock();  // 调用移动构造
    std::cout << std::endl;
    std::cout << std::endl;
    std::cout << std::endl;
    MemoryBlock &&tmp1(getMemoryBlock()); // 调用移动构造

    MemoryBlock tmp3(10);
    // 调用移动赋值
    tmp3 = std::move(m);  // std::move相当于强制类型转换,将左值转为右值,否则不能编译通过
    int mLentth = m.Length();  // mLentth为0 因为其内容已经移动到tmp3
    std::cout << "m length: " << mLentth;

    std::move(n2);
    mLentth = n2.Length();  // mLentth 不为0,因为虽然强转了一次,但并没有执行移动操作

    return 0;
}

右值引用和移动构造是两个相互独立的概念,只不过不是移动构造中需要用到右值引用,因为要通过右值引用来进行函数重载,如拷贝构造对应移动构造,拷贝赋值对应移动赋值

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-18 17:22:53  更:2022-04-18 17:24:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/23 23:43:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码