正文

C++11标准中借助右值引用可以为指定类添加移动构造函数,这样当使用给类的右值对象(可以理解为临时对象)初始化同类对象时,编译器会优先选择移动构造函数

注意,移动构造函数的调用时机是:用同类的右值对象初始化新对象。

那么,用当前类的左值对象(有名称,能获取其存储地址的实例对象)初始化同类对象时,是否就无法调用移动构造函数了呢?当前不是,C++11标准中已经给出了解决方案,即调用move()函数

  • move本意为”移动“,但是该函数并不能移动任何数据,它的功能很简单,就是将某个左值强制转换为右值
  • 基于move函数特有的功能,其常用于实现移动语义

move() 函数的用法也很简单,其语法格式如下:

move( arg )

其中,arg 表示指定的左值对象。该函数会返回 arg 对象的右值形式。

【例 1】move() 函数的基础应用。

#include <iostream>
using namespace std;
class movedemo{public:movedemo():num(new int(0)){cout<<"construct!"<<endl;}//拷贝构造函数movedemo(const movedemo &d):num(new int(*d.num)){cout<<"copy construct!"<<endl;}//移动构造函数movedemo(movedemo &&d):num(d.num){d.num = NULL;cout<<"move construct!"<<endl;}
public:     //这里应该是 private,使用 public 是为了更方便说明问题int *num;
};
int main(){movedemo demo;cout << "demo2:\n";movedemo demo2 = demo;//cout << *demo2.num << endl;   //可以执行cout << "demo3:\n";movedemo demo3 = std::move(demo);//此时 demo.num = NULL,因此下面代码会报运行时错误//cout << *demo.num << endl;return 0;
}

程序执行结果为:

construct!
demo2:
copy construct!
demo3:
move construct!

通过观察程序的输出结果,以及对比demo2demo3初始化操作不难得知,demo对象作为左值,直接用于初始化demo2对象,其底层调用的是拷贝构造函数;而通过调用move()函数可以得到demo对象的右值形式,用其初始化demo3对象,编译器会优先调用移动构造函数

注意:调用拷贝构造函数,并不影响demo对象,但是如果调用移动构造函数,函数内部会重置demo.num指针为null

【例 2】灵活使用 move() 函数。

#include <iostream>
using namespace std;
class first {public:first() :num(new int(0)) {cout << "construct!" << endl;}//移动构造函数first(first &&d) :num(d.num) {d.num = NULL;cout << "first move construct!" << endl;}
public:    //这里应该是 private,使用 public 是为了更方便说明问题int *num;
};
class second {public:second() :fir() {}//用 first 类的移动构造函数初始化 firsecond(second && sec) :fir(move(sec.fir)) {cout << "second move construct" << endl;}
public:    //这里也应该是 private,使用 public 是为了更方便说明问题first fir;
};
int main() {second oth;second oth2 = move(oth);//cout << *oth.fir.num << endl;   //程序报运行时错误return 0;
}

程序执行结果为:

construct!
first move construct!
second move construct

程序中分别构建了 first 和 second 这 2 个类,其中 second 类中包含一个 first 类对象。如果读者仔细观察不难发现,程序中使用了 2 此 move() 函数:

  • 程序第 31 行:由于 oth 为左值,如果想调用移动构造函数为 oth2 初始化,需先利用 move() 函数生成一个 oth 的右值版本;
  • 程序第 22 行:oth 对象内部还包含一个 first 类对象,对于 oth.fir 来说,其也是一个左值,所以在初始化 oth.fir 时,还需要再调用一次 move() 函数。

大部分情况下,我们需要转换成为右值引用的是一个生命期即将结束的对象,比如:

using namespace std;class HugeMem{public:HugeMem(int size) : sz(size > 0 ? size : 1){c = new int[sz];}~HugeMem() {delete [] c; }HugeMem(HugeMem && hm) : sz(hm.sz), c(hm.c){hm.c = nullptr;}int *c;int sz;
};class Moveable{public:Moveable() : i (new int(3)), h(1024){}~Moveable() {delete i;};Moveable(Moveable && m) :i(m.i), h(move(m.h)){  // 强制转换为右值,以调用移动构造函数m.i == nullptr;}int *i;HugeMem h;
};

实际上,为了保证移动语义的传递,程序员在编写移动构造函数的时候,应该总是记得使用std::move转换拥有比如堆内存、文件句柄等资源的成员为右值,这样一来,如果成员支持移动构造的话,就可以实现其移动语义。而即使成员没有移动构造函数,那么接受常量左值的构造函数版本也会轻松的实现拷贝构造,而不引起大问题

面试:说下std::move

  • 可以将左值强制转换为右值。目的是为了转移所有权,将快要销毁的对象转移给其他对象,这样就可以继续使用这个对象,可以避免拷贝一个一样的对象。提高了性能。

  • 实际上move发生的细节是由移动构造函数实现的,移动构造函数是一个右值

Book(Book&& iBook) {swap(this->mName, iBook.mName);mCount = 3;}

C/C++编程:std::move(将左值强制转换为右值)相关推荐

  1. move函数c语言,C++11 move()函数:将左值强制转换为右值

    通过学习 <C++11移动构造函数>一节我们知道,C++11 标准中借助右值引用可以为指定类添加移动构造函数,这样当使用该类的右值对象(可以理解为临时对象)初始化同类对象时,编译器会优先选 ...

  2. std::move C++11 标准新特性: 右值引用与转移语义

    新特性的目的 右值引用 (Rvalue Referene) 是 C++ 新标准 (C++11, 11 代表 2011 年 ) 中引入的新特性 , 它实现了转移语义 (Move Sementics) 和 ...

  3. C++左值、右值、左值引用、右值引用

    左值(lvalue)和右值(rvalue) 左值(lvalue):locator value,存储在内存中.有明确的的地址(可寻址)的数据 能够取地址,有名字的值就是左值 //左值引用 int a=1 ...

  4. java左值与右值问题_[C++11]左值、右值、左值引用、右值引用小结

    左值和右值 左值:指表达式结束后依然存在的持久对象,可以取地址,具名变量或对象 右值:表达式结束后就不再存在的临时对象,不可以取地址,没有名字. 比如 int a = b + c;,a 就是一个左值, ...

  5. [C++11]左值、右值、左值引用、右值引用小结

    左值和右值 左值:指表达式结束后依然存在的持久对象,可以取地址,具名变量或对象 右值:表达式结束后就不再存在的临时对象,不可以取地址,没有名字. 比如 int a = b + c;,a 就是一个左值, ...

  6. C++/C++11中左值、左值引用、右值、右值引用的使用

    C++的表达式要不然是右值(rvalue),要不然就是左值(lvalue).这两个名词是从C语言继承过来的,原本是为了帮助记忆:左值可以位于赋值语句的左侧,右值则不能. 在C++语言中,二者的区别就没 ...

  7. 【C++11】左值引用和右值引用

    目录 一.新的类功能 1.新的默认成员函数 2.类成员变量初始化 3.强制生成默认函数的关键字default 4.禁止生成默认函数的关键字delete 二.左值和右值 1.左值和左值引用 2.右值和右 ...

  8. C++ 左值与右值 左值引用与右值引用

    1 左值与右值 左值: 是可以取地址有名字的,非临时的都是左值.在内存中必须有实体. 右值: 不能取地址,没有名字,临时值是右值.在内存或者在寄存器中. 通俗点讲: 右值只能放在 = 号的右边 左值可 ...

  9. C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward

    这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运行测试过的,希望能用这些帮助理 ...

最新文章

  1. MySQL 设计规范(续)
  2. SpringBoot中在除controller以外注入service-过滤器中注入
  3. 安卓市场和安智市场_安卓市场小米市场ASO详解
  4. DbgPrint 格式字符串
  5. 组播IP地址到底是谁的IP?
  6. 数据开放 数据集_除开放式清洗之外:叙述是开放数据门户的未来吗?
  7. Pytorch框架中SGD&Adam优化器以及BP反向传播入门思想及实现
  8. linux任务计划cron
  9. LOJ2001 SDOI2017 树点涂色 LCT、线段树
  10. 126 MySQL存储引擎概述
  11. 6N137S周边电阻选择和传输速率(在开关特性中有描述,上升时间下降时间等参数)
  12. 光纤基础知识(2)-光纤接头(尾纤)ST,SC,LC,FC
  13. 哈工大《同义词词林》共享版的若干改进
  14. 《此生未完成》:她说,名利权情,没有一样是不辛苦的
  15. 用计算机计算的定义,计算(数学用语)_百度百科
  16. 盘点一些网站的反爬虫机制
  17. python numpy.fft.fft和ifft
  18. sublime显示当前文件的编码格式
  19. 关于eSIM的一些简单介绍
  20. 百度同步盘linux客户端,技术|Linux下百度云的Python客户端(支持Unicode)

热门文章

  1. 春节不断电之机器学习 —— 决策树
  2. 台式计算机连接无线,台式电脑怎么连WiFi无线网络
  3. 2020及2021年常被利用的30个软件漏洞
  4. Androi--内容提供器
  5. Django——创建数据库和表
  6. LZW压缩(解压缩)算法详解及源码
  7. ubuntu恢复被rm误删的数据及原理
  8. Pom.xml文件教程详解
  9. CSS控制背景图片自适应表格大小
  10. YUV图片查看器以及测试文件(YUV420)