C++右值引用和移动语义
创始人
2025-01-07 18:03:26
0次

目录

概念:

左值引用和右值引用

概念:

注意:

左值引用的意义

作函数参数

函数引用返回

右值引用的意义

诞生背景

移动构造

移动赋值

其他应用

万能引用和完美转发

默认的移动构造和移动赋值


概念:

左值:顾名思义,可以在等号左边出现的被叫做左值,左值可以取地址。

右值:只能在等号右边出现的值为右值,且右值不能取地址。

例如

//左值 int a = 2; string s="hello"; const int b=3; int* pa=&a; //右值 3;//字面常量 a + 2;//表达式 add(2, 3);//函数返回值

左值引用和右值引用

概念:

左值引用是用来引用左值的,给左值起别名:

int a = 2;//左值 int& ra = a;//左值引用

右值引用是用来引用右值的,给右值起别名:

int&& rc = 5;//右值引用

注意:

左值引用只能引用左值,因为如果引用右值会导致权限的放大:

int& ra = 2;//权限放大,编译错误

但是左值引用加上const就可以引用右值:

const int& ra = 2;

右值引用只能引用右值,但是可以引用move后的左值

int a = 2;//左值 int&& ra = move(a);

左值引用的意义

作函数参数

C++引用底层是C语言的指针,所以在作为函数参数时可以减少拷贝或者作为输出型参数使用。

void func(const string& s)//输入型参数,const&既可以减少拷贝又可以防止改变引用的实体 { 	cout << s << endl; } void add(int& a)//作为输出型参数 {     a=2; }

函数引用返回

出了函数栈帧,返回变量不会销毁的就可以用引用返回,减少拷贝。否则会导致内存越界。

string ss="hello"; const string& func() { 	return ss;//ss是全局变量,出函数栈帧不会销毁,用引用返回就不会生成临时变量 }

右值引用的意义

诞生背景

普通函数传值返回时,由于函数栈帧出作用域会销毁,其内定义的变量会被释放,所以会返回一个临时对象,这个临时对象是要返回对象的拷贝。

此时,我们会想:既然局部变量s马上就要销毁了,那么我们是否可以将它的资源交换给临时变量呢,这样临时变量的创建就不需要耗费拷贝的代价了。

C++把这种即将要销毁的自定义对象称为将亡值,在拷贝将亡值的时,可以利用右值引用在拷贝构造和赋值运算符重载函数中接收将亡值,并实现资源的置换,进而减少无意义的拷贝。

移动构造

在拷贝构造的实现中,实现一份形参使用右值引用接收的拷贝构造(即移动构造),当使用将亡值拷贝构造时,编译器会自动匹配移动构造,在移动构造内实现资源的互换。

移动赋值

在赋值运算符重载的实现中,实现一份形参使用右值引用接收的赋值运算符重载(即移动赋值),当使用将亡值赋值时,编译器会自动匹配移动赋值,在移动赋值内实现资源的互换。

C++11后,基本所有的STL容器都新增了移动构造和移动赋值,以此来提高需要深拷贝的容器是将亡值时的拷贝效率。

其他应用

除此之外,右值引用在其他接口中也大放异彩:

STL容器插入数据的接口:当插入需要深拷贝对象的右值时,减少拷贝

std::swap交换函数:

万能引用和完美转发

当函数模板和右值引用组合:万能引用既可以引用左值,又可以引用右值

万能引用又叫做引用折叠,即传入右值时&&,传入左值时折叠&。


右值引用的作用就是限制了接收变量只能是右值,但是右值引用本身会退化为左值:

template void func(T&& val)//万能引用 { 	cout << val << endl;//就算原本接收的是右值,右值引用val退化为左值 } int main() { 	func(10); 	return 0; }

完美转发:保留对象原生类型属性,即保持它的左值或者右值的属性

template void func(T&& val)//万能引用 { 	cout << std::forward(val) << endl;//这里使用完美转发保留传入之前的属性 } int main() { 	func(10); 	return 0; }

默认的移动构造和移动赋值

默认移动构造:

如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任
意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类
型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,
如果实现了就调用移动构造,没有实现就调用拷贝构造
。

解释:

分析上述定义,默认移动构造就是在析构函数 、拷贝构造、赋值重载都没有写,且移动构造也没有显式实现的情况下,编译器会默认生成。

当析构函数,拷贝构造、赋值重载都没有写的时候,且默认C++程序员没有犯错,那么这个类本身一定只含有内置类型成员或"自控"的自定义类型成员,没有需要手动释放的资源。

此时编译器就要做事了,默认生成一份移动构造,当别人调用默认移动构造,来将自定义类型中可以移动构造的对象自动调用移动构造,增加效率,非常合理。

反着思考:如果一个类内有资源需要手动释放,那么析构函数 、拷贝构造、赋值重载一定都要手动写,此时就算我们不手动写移动构造,编译器也不会默认生成,因为编译器不会知道哪些资源需要转移。

默认移动赋值完全类似。

相关内容

热门资讯

实测交流透视挂!宝玛大厅ai智... 实测交流透视挂!宝玛大厅ai智能透视挂教程,宝玛大厅破解软件经验(本来有挂辅助)1、每一步都需要思考...
总算了解辅助器!朱雀吴江三缺一... 总算了解辅助器!朱雀吴江三缺一ai智能透视辅助挂技巧,朱雀吴江三缺一好像是有挂(有辅助挂细节)朱雀吴...
今日公布透视!九五至尊大厅ai... 今日公布透视!九五至尊大厅ai智能透视插件,九五至尊大厅有没有透视挂窍门(切实有挂技术)1、在九五至...
玩家必看科普开挂!聚闲麻将ai... 玩家必看科普开挂!聚闲麻将ai智能透视辅助挂软件,聚闲麻将总是真的有挂(有辅助挂方式)聚闲麻将能透视...
据报道开挂!旅游娱乐ai智能开... 据报道开挂!旅游娱乐ai智能开挂工具,旅游娱乐辅助工具演示(一直有挂教学)1、全新机制【旅游娱乐ai...
一分钟揭秘开挂!决胜朋来麻将a... 一分钟揭秘开挂!决胜朋来麻将ai智能透视辅助挂教程,决胜朋来麻将真是真的是有挂(有辅助挂总结)1、首...
如何分辨真伪透视!红牛ai智能... 如何分辨真伪透视!红牛ai智能透视攻略,红牛是不是有挂经验(真是有挂技术)1、操作简单,无需红牛手机...
2分钟细说辅助器!江湖大庆麻将... 2分钟细说辅助器!江湖大庆麻将ai智能透视辅助挂攻略,江湖大庆麻将竟然是真的有挂(有辅助挂头条)1、...
总算清楚透视挂!老夫子厅ai智... 总算清楚透视挂!老夫子厅ai智能透视挂技巧,老夫子厅怎么开挂课程(好像发现有挂)老夫子厅破解侠是真的...
解密关于辅助!菜鸟麻将ai智能... 解密关于辅助!菜鸟麻将ai智能透视辅助挂脚本,菜鸟麻将总是存在有挂(有辅助挂存在)1、用户打开应用后...