返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >聊聊C++中右值引用和移动构造函数的使用
  • 646
分享到

聊聊C++中右值引用和移动构造函数的使用

2024-04-02 19:04:59 646人浏览 八月长安
摘要

目录一: 背景二: 右值引用1. 它到底解决了什么问题2. 右值引用是个什么样子三: 右值引用如何减少对象的创建1. 简要思路2. 一个简单的例子3. 性能优化方案四: 总结一: 背

一: 背景

最近在看 c++ 的右值引用和移动构造函数,感觉这东西一时半会还挺难理解的,可能是没踩过这方面的坑,所以没有那么大的深有体会,不管怎么说,这一篇我试着聊一下。

二: 右值引用

1. 它到底解决了什么问题

在其他编程语言中,很少听到 右值引用 这个词,我个人感觉还是 C++ 这个 值类型 优先的语言基因决定的,我们都知道 值类型 作为方法参数或者返回值时会生成自身的副本,如果 值类型 很大,那一来一回生成若干个深复制的 临时对象 将会产生巨大的性能开销。

总结一句话:右值引用 就是尽可能的减少这中间 临时对象 个数,尤其是关联到 heap 上的对象,仅此而已。

2. 右值引用是个什么样子

说到 右值引用 得先说什么是 右值,左值 , 左值 一般都是带有内存地址的变量,而 右值 一般是立即数或者运算过程中的临时对象,这种对象不会有地址值,是不是很绕,我举个例子吧。

int main()
{
	int i = 10;
	int j = 11;

	int sum = i + j;
}

1.10,11,(i+j)

属于右值,因为它本身没有内存地址,除非把它们放入到栈中或者堆中。

2.i,j,sum

属于左值,因为它们是线程栈上地址的标识符。

知道了 左右值 概念,接下来理解 左右值引用 就很简单了,既然是 引用,必然是多个变量指向同一个地址,对吧,修改下代码如下:

int main()
{
	int i = 10;
	int& k = i;		//左值引用


	int&& m = 10;	//右值引用
}

接下来看下汇编代码:

    33: 	int i = 10;
00FB182F  mov         dWord ptr [ebp-0Ch],0Ah  
    34: 	int& k = i;	
00FB182F  mov         dword ptr [ebp-0Ch],0Ah  
00FB1836  lea         eax,[ebp-0Ch]  
00FB1839  mov         dword ptr [ebp-18h],eax  
    36: 	int&& m = 10;	
00FB183C  mov         dword ptr [ebp-30h],0Ah  
00FB1843  lea         eax,[ebp-30h]  
00FB1846  mov         dword ptr [ebp-24h],eax 

从汇编代码看,它们是一模一样的,也就是说在汇编层面,其实并没有 右值引用 和 左值引用 一说。

有了这些基础,我们来看下更复杂的 class 结构。

三: 右值引用如何减少对象的创建

1. 简要思路

其实仔细想一想,减少临时对象的创建,无非就是在运算过程中复用一些对象,不需要每次都走赋值构造函数来进行深复制,画个图就像下面这样。

明白了这个思路,接下来我们举一个例子说明。

2. 一个简单的例子

C++ 最烦的地方就是有太多的构造函数, 数不胜数,太尴尬了,这里我做一个简单的 + 操作例子。

#include <iOStream>
#include <vector>

using namespace std;

class StringBuidler {
public:
	char* str;
	int length;
public:
	StringBuidler() {}
	StringBuidler(int len, char c) {
		this->str = new char[len];
		this->str[0] = c;
		this->length = len;
	}

	StringBuidler(const StringBuidler& s) {

		printf("StringBuidler:深复制 \n");
		this->length = s.length;
		this->str = new char[s.length];

		for (size_t i = 0; i < length; i++)
		{
			this->str[i] = s.str[i];
		}
	}

	StringBuidler operator+(const StringBuidler& p) {

		StringBuidler tmp;

		tmp.length = this->length + p.length;
		tmp.str = new char[tmp.length];

		int index = 0;

		for (size_t i = 0; i < this->length; i++)
		{
			tmp.str[index++] = this->str[i];
		}
		for (size_t i = 0; i < p.length; i++)
		{
			tmp.str[index++] = p.str[i];
		}

		return tmp;
	}
};

int main()
{
	StringBuidler s1(10, 'a');
	StringBuidler s2(5, 'b');

	StringBuidler s3 = s1 + s2;

	printf("s3.length=%d, s1.length=%d, s2.length=%d \n", s3.length, s1.length, s2.length);
}

从这个例子中可以看到,s1+s2 操作中出现了一次 深copy,具体代码出现在 return 处,汇编代码如下:

因为是深复制,所以会再次生成一个 new char[] ,如果 new char[] 很大,那将会是不必要的性能开销,能不能像我画的图一样,将 s3 中的 str 指针直接指向 tmp 所持有的 heap 上的 char[] 数组来达到复用目的呢? 肯定是可以的。

3. 性能优化方案

这里需要用 右值引用 + 移动构造函数 让 s3.str 指向 tmp.str,从而避免复制构造函数,在 StringBuilder 类中加一个方法如下:

	StringBuidler(StringBuidler&& s) {
		this->str = s.str;
		this->length = s.length;

		s.str = nullptr;
	}

然后把程序跑起来,截图如下:

可以看到,深复制已经没有了,这个过程会在 return 处被调用,编译器会判断如果是右值的话,自动走 移动构造函数,没有这个函数就会走 赋值构造函数。

四: 总结

总之右值引用 可以让你尽可能的复用一些中间对象,达到一个性能上的提升,其实对 C# 程序员来说,这么简单的引用赋值,C++ 搞出了这么多概念,真的很难理解,可能还是那句话,这是 C++ 的值类型优先的基因决定的。

到此这篇关于聊聊C++中右值引用和移动构造函数的使用的文章就介绍到这了,更多相关C++右值引用 移动构造函数内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: 聊聊C++中右值引用和移动构造函数的使用

本文链接: https://lsjlt.com/news/165212.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

猜你喜欢
  • 聊聊C++中右值引用和移动构造函数的使用
    目录一: 背景二: 右值引用1. 它到底解决了什么问题2. 右值引用是个什么样子三: 右值引用如何减少对象的创建1. 简要思路2. 一个简单的例子3. 性能优化方案四: 总结一: 背...
    99+
    2024-04-02
  • C++右值引用与移动构造函数基础与应用详解
    目录1.右值引用1.1左值右值的纯右值将亡值右值1.2右值引用和左值引用2.移动构造函数2.1完美的移动转发1.右值引用 右值引用是 C++11 引入的与 Lambda 表达式齐名的...
    99+
    2023-02-13
    C++右值引用 C++移动构造函数
  • C++移动构造函数和移动赋值的用法
    本篇内容介绍了“C++移动构造函数和移动赋值的用法”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!移动构造函数首先看通常的拷贝构造函数:拷贝构...
    99+
    2023-06-19
  • C++右值引用与移动构造函数应用的方法是什么
    这篇文章主要讲解了“C++右值引用与移动构造函数应用的方法是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++右值引用与移动构造函数应用的方法是什么”吧!1.右值引用右值引用是 C++...
    99+
    2023-07-05
  • C++11移动构造函数的使用
    目录一、引言二、左值和右值三、深拷贝构造函数四、右值引用五、移动构造函数六、std::move()七、参考资料一、引言 移动构造函数是什么?先举个例子,你有一本书,你不想看,但我很想...
    99+
    2024-04-02
  • 聊聊PHP中die()和sleep()函数的用法
    在上一篇《聊聊PHP中删除字符串的逗号和尾部斜杠的方法》给大家介绍了PHP删除字符串中的逗号以及尾部斜杠的方法,感兴趣的朋友可以去学习了解一下~ 本文也将给大家通过示例来讲解标题所述...
    99+
    2024-04-02
  • C++ 函数左侧值引用和右侧值引用参数的区别
    c++++中左侧和右侧值引用参数的不同之处如下:左侧值引用 (&) 指向已有对象,用于修改其状态。右侧值引用 (&&) 指向临时对象,用于获取或传递其数据。 C...
    99+
    2024-04-19
    参数 函数 引用 c++
  • C++11右值引用和移动语义的实例解析
    目录基本概念左值 vs 右值左值引用 vs 右值引用右值引用使用场景和意义左值引用的使用场景左值引用的短板右值引用和移动语义右值引用引用左值右值引用的其他使用场景完美转发万能引用完美...
    99+
    2024-04-02
  • 聊聊PHP escapeshellarg函数使用的中文问题
    本篇文章给大家带来了关于PHP escapeshellarg函数的相关知识,其中主要介绍了在命令行中调用 escapeshellarg函数有关中文字符的问题,感兴趣的朋友,下面一起来看一下吧,希望对大家有帮助。PHP 中命令行调用 esca...
    99+
    2023-05-14
    escapeshellarg php
  • C++11右值引用和移动语义的方法是什么
    本文小编为大家详细介绍“C++11右值引用和移动语义的方法是什么”,内容详细,步骤清晰,细节处理妥当,希望这篇“C++11右值引用和移动语义的方法是什么”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。左值引用与右值...
    99+
    2023-07-05
  • C++11学习之右值引用和移动语义详解
    目录左值引用与右值引用1、左值与右值2、纯右值、将亡值3、左值引用与右值引用4、右值引用和 std::move 使用场景引用限定符const 和引用限定符移动语义—std...
    99+
    2023-02-23
    C++11右值引用 移动语义 C++11右值引用 C++11 移动语义
  • C++中右值引用与移动语义的方法是什么
    今天小编给大家分享一下C++中右值引用与移动语义的方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。意义充分利用临时对...
    99+
    2023-07-05
  • C++中拷贝构造函数的使用
    目录拷贝构造函数1. 手动定义的拷贝构造函数2. 合成的拷贝构造函数总结拷贝构造函数 拷贝构造函数,它只有一个参数,参数类型是本类的引用。复制构造函数的参数可以是 const 引用,...
    99+
    2024-04-02
  • C#中构造函数如何使用
    C#中构造函数如何使用,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。C#构造函数在使用方面及行为方面的一些特殊规则:如果开发人员没有为一个类提供构造函数,那么,...
    99+
    2023-06-17
  • C#中怎么使用构造函数
    本篇文章给大家分享的是有关C#中怎么使用构造函数,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。C#构造函数的名字不能随便起,必须让编译器认得出才可以被自动执行。它的命名方法既简...
    99+
    2023-06-17
  • 一文带你了解C++中的右值引用与移动语义
    目录意义左值右值值类别左值纯右值将亡值左值引用右值引用std::move()移动构造&移动赋值运算符重载测试&验证意义 充分利用临时对象,避免拷贝。 左值右值 值类别...
    99+
    2023-05-13
    C++右值引用 移动语义 C++右值引用 C++ 移动语义
  • C#中构造函数和析构函数的作用是什么
    本篇文章给大家分享的是有关C#中构造函数和析构函数的作用是什么,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。C#构造函数(constructor)包括实例C#构造函数和静态C#...
    99+
    2023-06-17
  • C++中构造函数和析构函数有什么作用
    构造函数是一种特殊的成员函数,用于在创建对象时初始化对象的数据成员。构造函数的作用是初始化对象的状态,为对象的数据成员赋初值,确保对...
    99+
    2024-03-11
    C++
  • C#中如何使用结构体构造函数
    本篇文章给大家分享的是有关C#中如何使用结构体构造函数,小编觉得挺实用的,因此分享给大家学习,希望大家阅读完这篇文章后可以有所收获,话不多说,跟着小编一起来看看吧。///〈summary〉  ///启动服务端的参数结构&...
    99+
    2023-06-17
  • C#中的构造函数怎么用
    这篇文章主要介绍了C#中的构造函数怎么用的相关知识,内容详细易懂,操作简单快捷,具有一定借鉴价值,相信大家阅读完这篇C#中的构造函数怎么用文章都会有所收获,下面我们一起来看看吧。C# 中的构造函数类的 构造函数 是类的一...
    99+
    2023-06-17
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作