【C++干货铺】C++11新特性——右值引用、移动构造、完美转发

这篇具有很好参考价值的文章主要介绍了【C++干货铺】C++11新特性——右值引用、移动构造、完美转发。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

=========================================================================

个人主页点击直达:小白不是程序媛

C++系列专栏:C++干货铺

代码仓库:Gitee

=========================================================================

目录

左值与左值引用

右值与右值引用

左值引用和右值引用的比较

 左值引用总结:

右值引用总结:

左值引用的作用和意义

右值引用的使用场景和意义

移动赋值和移动构造

 完美转发

std::forward 完美转发在传参的过程中保留对象原生类型属性

​编辑新的类功能

默认成员函数

强制生成默认函数的关键字default

禁止生成默认函数的关键字delete

继承和多态中的final与override关键字


【C++干货铺】C++11新特性——右值引用、移动构造、完美转发,C++干货铺,c++,开发语言,C++11,移动构造,移动赋值

左值与左值引用

传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,所以从现在开始我们
之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名。

什么是左值?什么是左值引用

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引用就是给左值的引用,给左值取别名

//左值与左值引用
int main()
{
	//左值
	//可以取到地址
	int* p = new int(0);
	int b = 1;
	const int c = 2;
	//左值引用
	int*& rp = p;
	int& rb = b;
	const int& rc = c;
	int& pvalue= *p;
	return 0;
}

右值与右值引用

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址右值引用就是对右值的引用,给右值取别名

//右值与右值引用
int main()
{
	//右值
	//右值不可以被取地址
	double x = 1.1, y = 2.2;
	10;
	x + y;
	fmin(x, y);
	//右值引用
	int&& rr1 = 10;
	double&& rr2 = x + y;
	double&& rr3 = fmin(x, y);

	return 0;
}

左值引用和右值引用的比较

 左值引用总结:

  • 1. 左值引用只能引用左值,不能引用右值。
  • 2. 但是const左值引用既可引用左值,也可引用右值。

右值引用总结:

  • 1. 右值引用只能右值,不能引用左值。
  • 2. 但是右值引用可以move以后的左值。
//左值引用和右值引用的比较
int main()
{
	//左值引用
	int a = 10;
	int& ra = a;
	//const 左值引用既可以引用左值又可以引用右值
	const int& ra1 = a;
	const int& ra2 = 10;

	//右值引用
	//不可以引用左值
	/*int&& r1 = a;*/
	//使用mova后可以
	int&& r1 = move(a);
	int&& r1 = 10;

	return 0;

}

左值引用的作用和意义

左值引用可以做函数的参数和函数的返回值,这样可以避免在函数传参和函数返回的时候去进行各种拷贝构造,对于一些大对象和需要进行深拷贝的对象来说,这样做可以提高效率。

左值引用的缺陷:当函数返回的对象是一个局部变量时,出了函数的作用域该对象就被销毁了,就不能使用左值引用返回,只能通过传值返回。而传值返回会导致至少调用一次拷贝构造,如果是旧一点的编译器可能是调用两次构造函数。。

    //MyString
    string& to_string(int x)
	{
		string ret;
		while (x)
		{
			int val = x % 10;
			x = x / 10;
			ret += ('0' + val);
		}
		reverse(ret.begin(), ret.end());
		return ret;
	}



int main()
{
	bit::string s; 
	s= to_string(1234);
	return 0;
}

【C++干货铺】C++11新特性——右值引用、移动构造、完美转发,C++干货铺,c++,开发语言,C++11,移动构造,移动赋值


右值引用的使用场景和意义

其实右值含有两种形式

  • 纯右值:编写程序时所出现的的字面值常属于纯右值
  • 将亡值:自定义类型的临时对象

右值引用的出现完全是为了解决左值引用的缺陷的;


移动赋值和移动构造

还是对上面的代码进行分析

【C++干货铺】C++11新特性——右值引用、移动构造、完美转发,C++干货铺,c++,开发语言,C++11,移动构造,移动赋值

注:上面的代码我们先生成一个临时对象ret,函数调用结束会销毁栈帧;因此ret拷贝构造在生成一个临时对象,在由这个临时对象深拷贝生成String类的s。为了实例化这个对象我们进行了两次临时对象的创建,在由这两个临时对象进行两次深拷贝;对于很大的类时,进行这样的操作是非常浪费时间和空间的;由于中间产生了临时值(这个临时值就是我们上面所说的将亡值),而恰好临时值取不到地址是一个右值,我们可以对其引用使用移动赋值。

string& operator=(string&& s)
{
	cout << "string& operator=(string&& s) -- 移动语义" << endl;
	swap(s);
	return *this;
}

只需要重载一个右值引用参数类型的重载函数即可。

【C++干货铺】C++11新特性——右值引用、移动构造、完美转发,C++干货铺,c++,开发语言,C++11,移动构造,移动赋值

函数调用结束需要销毁栈帧编译器识别ret为一个临时值,并且这个临时值需要拷贝在产生一个临时值return返回调用移动拷贝交换数据即可,释放ret;函数返回的临时值需要赋值给另外一个同类型的值,编译器识别进行移动赋值,交换数据释放临时值;这个过程就是移动赋值,及减少了临时对象的产生(将亡值),又减少了深拷贝。对于一些大的类来说进行连续的赋值节省了空间和时间。

移动构造和移动赋值的原理差不多,这里不进行过度赘述。

注:目前比较新的编译器会对连续的拷贝构造进行优化。


完美转发

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }

template<typename T>
void PerfectForward(T&& t)
{
	Fun(t);
}
int main()
{
	PerfectForward(10);           // 右值
	int a;
	PerfectForward(a);            // 左值
	PerfectForward(std::move(a)); // 右值
	const int b = 8;
	PerfectForward(b);      // const 左值
	PerfectForward(std::move(b)); // const 右值
	return 0;
}

【C++干货铺】C++11新特性——右值引用、移动构造、完美转发,C++干货铺,c++,开发语言,C++11,移动构造,移动赋值

这是什么情况? 

模板中的&&不代表右值引用,而是万能引用,其既能接收左值又能接收右值。模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力,但是引用类型的唯一作用就是限制了接收的类型,后续使用中都退化成了左值,我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发。

注:你也可以这样理解上面的PerfectForward函数其实是左值引用和右值引用是重载的,当传入左值时候重载,直接调用Fun函数;当传入右值时,刚好符合参数进行右值引用,但是右值的右值引用的属性是左值,因此调用Fun函数也是左值引用。

std::forward 完美转发在传参的过程中保留对象原生类型属性

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }

void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }

template<typename T>
void PerfectForward(T&& t)
{
	//完美转发
	Fun(forward<T>(t));
}

int main()
{
	PerfectForward(10);           // 右值

	int a;
	PerfectForward(a);            // 左值
	PerfectForward(std::move(a)); // 右值

	const int b = 8;
	PerfectForward(b);		      // const 左值
	PerfectForward(std::move(b)); // const 右值

	return 0;
}

【C++干货铺】C++11新特性——右值引用、移动构造、完美转发,C++干货铺,c++,开发语言,C++11,移动构造,移动赋值


新的类功能

默认成员函数

原来C++类中,有6个默认成员函数:

  • 1. 构造函数
  • 2. 析构函数
  • 3. 拷贝构造函数
  • 4. 拷贝赋值重载
  • 5. 取地址重载
  • 6. const 取地址重载

最后重要的是前4个,后两个用处不大。默认成员函数就是我们不写编译器会生成一个默认的。
C++11 新增了两个:移动构造函数移动赋值运算符重载

针对移动构造函数和移动赋值运算符重载有一些需要注意的点如下:

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

强制生成默认函数的关键字default

C++11可以让你更好的控制要使用的默认函数。假设你要使用某个默认的函数,但是因为一些原因这个函数没有默认生成。比如:我们提供了拷贝构造,就不会生成移动构造了,那么我们可以使用default关键字显示指定移动构造生成。

禁止生成默认函数的关键字delete

如果能想要限制某些默认函数的生成,在C++98中,是该函数设置成private,并且只声明补丁已,这样只要其他人想要调用就会报错。在C++11中更简单,只需在该函数声明加上=delete即可,该语法指示编译器不生成对应函数的默认版本,称=delete修饰的函数为删除函数。

继承和多态中的final与override关键字

这个我们在继承和多态章节已经进行了详细讲解这里就不再细讲,需要的话去复习继承和多态那篇文章吧。


今天给大家分享介绍了C++11中的右值引用和移动构造。如果觉得文章还不错的话,可以三连支持一下,个人主页还有很多有趣的文章,欢迎小伙伴们前去点评,您的三连支持就是我前进的动力!文章来源地址https://www.toymoban.com/news/detail-823540.html

到了这里,关于【C++干货铺】C++11新特性——右值引用、移动构造、完美转发的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【重学C++】04 | 说透C++右值引用、移动语义、完美转发(上)

    【重学C++】04 | 说透C++右值引用、移动语义、完美转发(上) 大家好,我是只讲技术干货的会玩code,今天是【重学C++】的第四讲,在前面《03 | 手撸C++智能指针实战教程》中,我们或多或少接触了右值引用和移动的一些用法。 右值引用是 C++11 标准中一个很重要的特性。第一

    2024年02月06日
    浏览(45)
  • 【重学C++】05 | 说透右值引用、移动语义、完美转发(下)

    【重学C++】05 | 说透右值引用、移动语义、完美转发(下) 大家好,我是只讲技术干货的会玩code,今天是【重学C++】的第五讲,在第四讲《【重学C++】04 | 说透右值引用、移动语义、完美转发(上)》中,我们解释了右值和右值引用的相关概念,并介绍了C++的移动语义以及如

    2024年02月06日
    浏览(40)
  • C++右值引用(左值表达式、右值表达式)(移动语义、完美转发(右值引用+std::forward))(有问题悬而未决)

    在 C++ 中,表达式可以分为左值表达式和右值表达式。左值表达式指的是可以出现在赋值语句左边的表达式,例如变量、数组元素、结构体成员等;右值表达式指的是不能出现在赋值语句左边的表达式,例如常量、临时对象、函数返回值等。 右值是指将要被销毁的临时对象或

    2024年02月04日
    浏览(45)
  • 【C++】—— C++11新特性之 “右值引用和移动语义”

    前言: 本期,我们将要的介绍有关 C++右值引用 的相关知识。对于本期知识内容,大家是必须要能够掌握的,在面试中是属于重点考察对象。 目录 (一)左值引用和右值引用 1、什么是左值?什么是左值引用? 2、什么是右值?什么是右值引用? (二)左值引用与右值引用比

    2024年02月11日
    浏览(42)
  • C++11『右值引用 ‖ 完美转发 ‖ 新增类功能 ‖ 可变参数模板』

    ✨个人主页: 北 海 🎉所属专栏: C++修行之路 🎃操作环境: Visual Studio 2022 版本 17.6.5 自从C++98以来,C++11无疑是一个相当成功的版本更新。它引入了许多重要的语言特性和标准库增强,为C++编程带来了重大的改进和便利。C++11的发布标志着C++语言的现代化和进步,为程序员

    2024年02月05日
    浏览(50)
  • C++——移动构造和完美转发

    右值引用是C++11的概念,与之对应的是左值引用。 当一个对象被用作右值的时候,用的是对象的值(内容);当对象被用作左值的时候,用的是对象的身份(在内存当中的位置)。 以上的概念是摘录自《C++ primer》。 但是这样的概念并不足以理解。 用一句简单的话描述左值和右值

    2024年02月12日
    浏览(35)
  • 【C++】 C++11(右值引用,移动语义,bind,包装器,lambda,线程库)

    C++11是C++语言的一次重大更新版本,于2011年发布,它包含了一些非常有用的新特性,为开发人员提供了更好的编程工具和更好的编程体验,使得编写高效、可维护、安全的代码更加容易。 一些C++11的新增特性包括: 强制类型枚举,使得枚举类型的通常行为更加可靠和容易控制

    2024年02月10日
    浏览(44)
  • C++左值右值完美转发转移

    英文含义: 左值(Lvalue) : Locator value ,意味着它指向一个具体的内存位置。 右值(Rvalue) : Read value ,指的是可以读取的数据,但不一定指向一个固定的内存位置。 定义 左值 :指的是一个持久的内存地址。左值可以出现在赋值操作的左侧或右侧。例如,变量、数组的元

    2024年03月10日
    浏览(55)
  • c++积累8-右值引用、移动语义

    1.1 背景 c++98中的引用很常见,就是给变量取个别名,具体可以参考c++积累7 在c++11中,增加了右值引用的概念,所以c++98中的引用都称为左值引用 1.2 定义 右值引用就是给右值取个名字,右值有了名字之后就成了普通变量,可以像使用左值一样使用。 语法:数据类型 变量名

    2023年04月23日
    浏览(37)
  • 【C++】C++11右值引用

    👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》 《数据结构》 《蓝桥杯试题》 《LeetCode刷题笔记》 《实训项目》 《C++》 《Linux》 《算法》 🌝 每一个不曾起舞的日子,都是对生命的辜负 目录 前言 1.什么是左值什么是右值 左值 右值 2.什么是左值引用什么是右值引用 左

    2024年04月22日
    浏览(49)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包