【C++】右值引用

文章目录

  • 右值引用
  • 值得形式返回对象的缺陷
  • 移动语句
  • 移动赋值

右值引用

能够取地址、能够被修改的被称之为左值。

不能够取地址、不能够被修改、以及将亡值被称之为右值。

  1. 普通类型的变量,因为有名字,可以取地址,都认为是左值。
  2. const修饰的常量,不可修改,只读类型的,理论应该按照右值对待,但因为其可以取地址(如果只是 const类型常量的定义,编译器不给其开辟空间,如果对该常量取地址时,编译器才为其开辟空间), C++11认为其是左值。
  3. 如果表达式的运行结果是一个临时变量或者对象,认为是右值。
  4. 如果表达式运行结果或单个变量是一个引用则认为是左值。

C++11对右值进行了严格的区分: C语言中的纯右值,比如:a+b, 100 将亡值。比如:表达式的中间结果、函数按照值的方式进行返回。

#include<iostream>
using namespace std;

void test(int a=0)
{
    return a;//a是将亡值
}

int main(void)
{
    int a=10;//a是左值,10是右值
    int b=20;//b是左值,20是右值
    b=a;//左值a也可以放在等于号=右边
    
    return 0;
}

值得形式返回对象的缺陷

#include<iostream>
#include<string>
using namespace std;


class String
{
public:
	String(const char* str = "")
	{
		cout << "构造函数()->String(const char* str = "")" << endl;
		if (nullptr == str)
		str = "";
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	String(const String & s)
	: _str(new char[strlen(s._str) + 1])
	{
		strcpy(_str, s._str);
	}

	String& operator=(const String& s)
	{
		 if (this != &s)
		 {
			 char* pTemp = new char[strlen(s._str) + 1];
			 strcpy(pTemp, s._str);
			 delete[] _str;
			 _str = pTemp;
		 }	
		return *this;
	}

 String operator+(const String& s)
 {
	 char* pTemp = new char[strlen(_str) + strlen(s._str) + 1];
	 strcpy(pTemp, _str);
	 strcpy(pTemp + strlen(_str), s._str);
	 String strRet(pTemp);
	 return strRet;
 }

 ~String()
 {
	 if (_str) delete[] _str;
 }
private:
	char* _str;
};
int main()
{
	String s1("hello");
	String s2("world");
	String s3=s1 + s2;
	return 0;
}

对于如上代码的operator+中,返回strRet的时候需要临时创建一个对象,然后销毁strRet,最后再把strRets3

这乍一看是没什么问题,但是这里的strRet临时对象s3的内容是完全相同的,但是开辟了三块空间,是不是太浪费空间了。

移动语句

C++11当中,如果需要实现移语句,必须使用右值引用。

#include<iostream>
using namespace std;


class String
{
public:
	String(const char* str = "")
	{
		cout << "构造函数()->String(const char* str = "")" << endl;
		if (nullptr == str)
		str = "";
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	String(const String & s)
		: _str(new char[strlen(s._str) + 1])
	{
		strcpy(_str, s._str);
	}

	void swap(String& s)
	{
		std::swap(_str,s._str);
	}

	String(String&& s)noexcept
		:_str(nullptr)
	{
		swap(s);
	}


	String& operator=(const String& s)
	{
		 if (this != &s)
		 {
			 char* pTemp = new char[strlen(s._str) + 1];
			 strcpy(pTemp, s._str);
			 delete[] _str;
			 _str = pTemp;
		 }	
		return *this;
	}

 String operator+(const String& s)
 {
	 char* pTemp = new char[strlen(_str) + strlen(s._str) + 1];
	 strcpy(pTemp, _str);
	 strcpy(pTemp + strlen(_str), s._str);
	 String strRet(pTemp);
	 return strRet;
 }

 ~String()
 {
	 if (_str) delete[] _str;
 }
private:
	char* _str;
};
int main()
{
	String s1("hello");
	String s2("world");
	String s3=(s1 + s2);
	return 0;
}

代码添加一个移动构造,就可以减少申请空间,在strRet返回的时候会去调用String(String&& s)noexcept,调用String(String&& s)noexcept的时候可以看到,直接把sthis中的资源做了交换,出了作用域,s就会被销毁,那么在销毁之前把资源先给this不是就可以减少拷贝了吗?

移动赋值

移动赋值和移动构造一样,可以减少拷贝,将现有的资源最大利用,减少空间的开辟。

#include<iostream>
using namespace std;


class String
{
public:
	String(const char* str = "")
	{
		cout << "构造函数()->String(const char* str = "")" << endl;
		if (nullptr == str)
		str = "";
		_str = new char[strlen(str) + 1];
		strcpy(_str, str);
	}

	String(const String & s)
		: _str(new char[strlen(s._str) + 1])
	{
		strcpy(_str, s._str);
	}

	void swap(String& s)
	{
		std::swap(_str,s._str);
	}

	//移动构造
	String(String&& s)noexcept
		:_str(nullptr)
	{
		cout << "移动构造(资源移动)" << endl;
		swap(s);
	}

	// 移动赋值
	String& operator=(String&& s)noexcept
	{
		cout << "String& operator=(string s) -- 移动赋值(资源移动)" << endl;
		swap(s);

		return *this;
	}


	String& operator=(const String& s)
	{
		 if (this != &s)
		 {
			 char* pTemp = new char[strlen(s._str) + 1];
			 strcpy(pTemp, s._str);
			 delete[] _str;
			 _str = pTemp;
		 }	
		return *this;
	}

 String operator+(const String& s)
 {
	 char* pTemp = new char[strlen(_str) + strlen(s._str) + 1];
	 strcpy(pTemp, _str);
	 strcpy(pTemp + strlen(_str), s._str);
	 String strRet(pTemp);
	 return strRet;
 }

 ~String()
 {
	 if (_str) delete[] _str;
 }
private:
	char* _str;
};
int main()
{
	String s1("hello");
	String s2("world");
	String s3=(s1 + s2);
	s3 = move(s1);//强行转换成将亡值
	return 0;
}

这里的move就是强制类型转化成一个将亡值,让其变成右值,好去调用我们这里的移动赋值(这里只是为了强行调用移动赋值,这样的代码其实是有问题的,会导致s1变成nullptr)。

move(s1)==static_cast<String&&>(s1);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/60932.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Flutter游戏引擎Flame系列笔记 - 1.Flame引擎概述

Flutter游戏引擎Flame系列笔记 1.Flame引擎概述 - 文章信息 - Author: 李俊才(jcLee95) Visit me at: https://jclee95.blog.csdn.netEmail: 291148484163.com. Shenzhen ChinaAddress of this article:https://blog.csdn.net/qq_28550263/article/details/132119035 【介绍】…

ThinkPHP v6.0.8 CacheStore 反序列化漏洞

漏洞说明 1. 漏洞原理&#xff1a;ThinkPHP 6.0.8 CacheStore 会触发POP利用链子&#xff0c;造成任意命令执行 2. 组件描述&#xff1a; ThinkPHP是一个免费开源的&#xff0c;快速、简单的面向对象的轻量级PHP开发框架 3. 影响版本&#xff1a;V6.0.8 漏洞复现 1. 环境安…

QtAV for ubuntu16.04

下载ubuntu https://releases.ubuntu.com/16.04/ubuntu-16.04.7-desktop-amd64.iso 下载ffmpeg https://ffmpeg.org/download.html 下载QtAV https://github.com/wang-bin/QtAV/releases 更新 sudo apt update 安装库 sudo apt-get install libglu1-mesa-dev freeglut3-dev…

解密爬虫ip是如何被识别屏蔽的

在当今信息化的时代&#xff0c;网络爬虫已经成为许多企业、学术机构和个人不可或缺的工具。然而&#xff0c;随着网站安全防护的升级&#xff0c;爬虫ip往往容易被识别并屏蔽&#xff0c;给爬虫工作增加了许多困扰。在这里&#xff0c;作为一家专业的爬虫ip供应商&#xff0c;…

K8s中的Secret

Secret作用&#xff1a;加密数据存在etcd里面&#xff0c;让pod容器以挂载Volume方式进行访问。场景&#xff1a;凭据

【经济调度】基于多目标宇宙优化算法优化人工神经网络环境经济调度研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

MySql的Windows安装指南

目录 一、MySQL的4大版本 二、软件的下载 三、MySQL8.0 版本的安装 四、配置MySQL8.0 五、配置MySQL8.0 环境变量 六、登录验证 一、MySQL的4大版本 MySQL Community Server 社区版本&#xff0c;开源免费&#xff0c;自由下载&#xff0c;但不提供官方技术支持&#xff…

5个顶级的开源有限元分析软件

每当我参加数值分析课程的教学时&#xff0c;都会回顾有限元方法的基础知识&#xff0c;很自然地就会出现使用哪种软件的问题。 以下讨论基于三个基本考虑&#xff1a; 在实际应用中&#xff0c;很少有人从头开始编写 FEM 代码。商业 FEM 软件通常在某些预定义的情况下非常易于…

EventBus 开源库学习(三)

源码细节阅读 上一节根据EventBus的使用流程把实现源码大体梳理了一遍&#xff0c;因为精力有限&#xff0c;所以看源码都是根据实现过程把基本流程看下&#xff0c;中间实现细节先忽略&#xff0c;否则越看越深不容易把握大体思路&#xff0c;这节把一些细节的部分再看看。 …

STM32的电动自行车信息采集上报系统(学习)

摘要 针对电动自行车实时监管不便的问题&#xff0c;设计了一种基于STM32的电动自行车信息采集系统&#xff0c;通过获取电池、位置和行驶状态信息并上报到服务器中&#xff0c;实现实时监管。 通过多路串口请求电池、行驶状态和位置信息&#xff0c;以并发方式进行数据接收、…

机器学习概述及其主要算法

目录 1、什么是机器学习 2、数据集 2.1、结构 3、算法分类 4、算法简介 4.1、K-近邻算法 4.2、贝叶斯分类 4.3、决策树和随机森林 4.4、逻辑回归 4.5、神经网络 4.6、线性回归 4.7、岭回归 4.8、K-means 5、机器学习开发流程 6、学习框架 1、什么是机器学习 机器…

Linux命令200例:用Look一个进行文本搜索工具

&#x1f3c6;作者简介&#xff0c;黑夜开发者&#xff0c;全栈领域新星创作者✌&#xff0c;阿里云社区专家博主&#xff0c;2023年6月csdn上海赛道top4。 &#x1f3c6;数年电商行业从业经验&#xff0c;历任核心研发工程师&#xff0c;项目技术负责人。 &#x1f3c6;本文已…

Web压测工具http_load原理分析

01、前言 http_load是一款测试web服务器性能的开源工具&#xff0c;从下面的网址可以下载到最新版本的http_load&#xff1a; http://www.acme.com/software/http_load/ 这个软件一直在保持着更新&#xff08;不像webbench&#xff0c;已经是十年的老古董了。 webbench的源…

Pandas

系列文章目录 第一章 python数据挖掘基础环境安装和使用 第二章 Matplotlib 第三章 Numpy 文章目录 系列文章目录一、介绍1.1 为什么用Pandas&#xff1f;1.2 核心数据结构1.3 DataFrame1.3.1 结构1.3.2 常用属性1.3.3 常用方法1.3.4 DataFrame索引的设置修改行列索引值重设索…

小白电脑装机(自用)

几个月前买了配件想自己装电脑&#xff0c;结果最后无法成功点亮&#xff0c;出现的问题是主板上的DebugLED黄灯常亮&#xff0c;即DRAM灯亮。对于微星主板的Debug灯&#xff0c;其含义这篇博文中有说明。 根据另一篇博文&#xff0c;有两种可能。 我这边曾将内存条和主板一块…

gin框架学习

文章目录 配置go环境实现一个简单的web响应服务验证功能gin增加页面以及传递数据 配置go环境 去go官网下载对应的版本 go下载地址 tar -C /usr/local -xzf go1.4.linux-amd64.tar.gz 我们可以编辑 ~/.bash_profile 或者 /etc/profile&#xff0c;并将以下命令添加该文件的末…

【新版系统架构补充】-传输介质、子网划分

传输介质 双绞线&#xff1a;无屏蔽双绞线UTP和屏蔽双绞线STP&#xff0c;传输距离在100m内 网线安装标准&#xff1a; 光纤&#xff1a;由纤芯和包层组成&#xff0c;分多模光纤MMF、单模光纤SMF 无线信道&#xff1a;分为无线电波和红外光波 通信方式和交换方式 单工…

使用隧道HTTP时如何解决网站验证码的问题?

使用代理时&#xff0c;有时候会遇到网站验证码的问题。验证码是为了防止机器人访问或恶意行为而设置的一种验证机制。当使用代理时&#xff0c;由于请求的源IP地址被更改&#xff0c;可能会触发网站的验证码机制。以下是解决网站验证码问题的几种方法&#xff1a; 1. 使用高匿…

Golang 函数参数的传递方式 值传递,引用传递

基本介绍 我们在讲解函数注意事项和使用细节时&#xff0c;已经讲过值类型和引用类型了&#xff0c;这里我们再系统总结一下&#xff0c;因为这是重难点&#xff0c;值类型参数默认就是值传递&#xff0c;而引用类型参数默认就是引用传递。 两种传递方式&#xff08;函数默认都…

前端主题切换方案——CSS变量

前言 主题切换是前端开发中老生常谈的问题&#xff0c;本文将介绍主流的前端主题切换实现方案——CSS变量 CSS变量 简介 编写CSS样式时&#xff0c;为了避免代码冗余&#xff0c;降低维护成本&#xff0c;一些CSS预编译工具&#xff08;Sass/Less/Stylus&#xff09;等都支…