C/C++编程:std::move(将左值强制转换为右值)
正文
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!
通过观察程序的输出结果,以及对比demo2
和demo3
初始化操作不难得知,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(将左值强制转换为右值)相关推荐
- move函数c语言,C++11 move()函数:将左值强制转换为右值
通过学习 <C++11移动构造函数>一节我们知道,C++11 标准中借助右值引用可以为指定类添加移动构造函数,这样当使用该类的右值对象(可以理解为临时对象)初始化同类对象时,编译器会优先选 ...
- std::move C++11 标准新特性: 右值引用与转移语义
新特性的目的 右值引用 (Rvalue Referene) 是 C++ 新标准 (C++11, 11 代表 2011 年 ) 中引入的新特性 , 它实现了转移语义 (Move Sementics) 和 ...
- C++左值、右值、左值引用、右值引用
左值(lvalue)和右值(rvalue) 左值(lvalue):locator value,存储在内存中.有明确的的地址(可寻址)的数据 能够取地址,有名字的值就是左值 //左值引用 int a=1 ...
- java左值与右值问题_[C++11]左值、右值、左值引用、右值引用小结
左值和右值 左值:指表达式结束后依然存在的持久对象,可以取地址,具名变量或对象 右值:表达式结束后就不再存在的临时对象,不可以取地址,没有名字. 比如 int a = b + c;,a 就是一个左值, ...
- [C++11]左值、右值、左值引用、右值引用小结
左值和右值 左值:指表达式结束后依然存在的持久对象,可以取地址,具名变量或对象 右值:表达式结束后就不再存在的临时对象,不可以取地址,没有名字. 比如 int a = b + c;,a 就是一个左值, ...
- C++/C++11中左值、左值引用、右值、右值引用的使用
C++的表达式要不然是右值(rvalue),要不然就是左值(lvalue).这两个名词是从C语言继承过来的,原本是为了帮助记忆:左值可以位于赋值语句的左侧,右值则不能. 在C++语言中,二者的区别就没 ...
- 【C++11】左值引用和右值引用
目录 一.新的类功能 1.新的默认成员函数 2.类成员变量初始化 3.强制生成默认函数的关键字default 4.禁止生成默认函数的关键字delete 二.左值和右值 1.左值和左值引用 2.右值和右 ...
- C++ 左值与右值 左值引用与右值引用
1 左值与右值 左值: 是可以取地址有名字的,非临时的都是左值.在内存中必须有实体. 右值: 不能取地址,没有名字,临时值是右值.在内存或者在寄存器中. 通俗点讲: 右值只能放在 = 号的右边 左值可 ...
- C++ 11 左值,右值,左值引用,右值引用,std::move, std::foward
这篇文章要介绍的内容和标题一致,关于C++ 11中的这几个特性网上介绍的文章很多,看了一些之后想把几个比较关键的点总结记录一下,文章比较长.给出了很多代码示例,都是编译运行测试过的,希望能用这些帮助理 ...
最新文章
- MySQL 设计规范(续)
- SpringBoot中在除controller以外注入service-过滤器中注入
- 安卓市场和安智市场_安卓市场小米市场ASO详解
- DbgPrint 格式字符串
- 组播IP地址到底是谁的IP?
- 数据开放 数据集_除开放式清洗之外:叙述是开放数据门户的未来吗?
- Pytorch框架中SGD&Adam优化器以及BP反向传播入门思想及实现
- linux任务计划cron
- LOJ2001 SDOI2017 树点涂色 LCT、线段树
- 126 MySQL存储引擎概述
- 6N137S周边电阻选择和传输速率(在开关特性中有描述,上升时间下降时间等参数)
- 光纤基础知识(2)-光纤接头(尾纤)ST,SC,LC,FC
- 哈工大《同义词词林》共享版的若干改进
- 《此生未完成》:她说,名利权情,没有一样是不辛苦的
- 用计算机计算的定义,计算(数学用语)_百度百科
- 盘点一些网站的反爬虫机制
- python numpy.fft.fft和ifft
- sublime显示当前文件的编码格式
- 关于eSIM的一些简单介绍
- 百度同步盘linux客户端,技术|Linux下百度云的Python客户端(支持Unicode)