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++程序员没有犯错,那么这个类本身一定只含有内置类型成员或"自控"的自定义类型成员,没有需要手动释放的资源。

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

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

默认移动赋值完全类似。

相关内容

热门资讯

黑科技数据(手机德州app)外... 黑科技数据(手机德州app)外挂透明挂辅助器(透视)从来真的有挂(有挂总结)-哔哩哔哩;相信小伙伴都...
黑科技辅助!wpk外挂第一视角... 黑科技辅助!wpk外挂第一视角(透视)软件透明挂ai辅助器(其实有挂)-哔哩哔哩;黑科技辅助!wpk...
黑科技辅助!wpk ai辅助购... 黑科技辅助!wpk ai辅助购买(透视)素来是有挂(详细教程)-哔哩哔哩;1、让任何用户在无需AI插...
黑科技辅助(来玩德州app)外... 黑科技辅助(来玩德州app)外挂透明挂辅助挂(透视)详细教程(2026已更新)(哔哩哔哩)是一款可以...
黑科技辅助!wpk辅助(透视)... 黑科技辅助!wpk辅助(透视)软件透明挂ai辅助下载(从来真的是有挂)-哔哩哔哩;wpk辅助软件透明...
黑科技中牌率(AAPoKer猫... 黑科技中牌率(AAPoKer猫腻)外挂透明挂辅助安装(透视)从来真的是有挂(有挂方式)-哔哩哔哩是一...
黑科技辅助!德州扑克助手(透视... 您好,德州扑克助手这款游戏可以开挂的,确实是有挂的,需要了解加微【136704302】很多玩家在这款...
黑科技辅助(pokerist)... 黑科技辅助(pokerist)外挂透明挂辅助黑科技(透视)必赢方法(2020已更新)(哔哩哔哩);致...
黑科技辅助!红龙扑克可以看底牌... 黑科技辅助!红龙扑克可以看底牌(透视)软件透明挂ai辅助代打(本然真的有挂)-哔哩哔哩是一款可以让一...
黑科技脚本(德扑ai代打)外挂... 黑科技脚本(德扑ai代打)外挂透明挂辅助挂(透视)果然真的是有挂(有挂技巧)-哔哩哔哩;AI辅助机器...