[JUCE]从一个有关右值引用的bug,探幽移动语义

一、问题

当我尝试在\JUCE\extras\WindowsDLL\Builds\VisualStudio2022目录下编译JUCE库的时候,提示报错如下:

在这里插入图片描述

报错提示如下:

在这里插入图片描述

这里涉及到两个问题

一、这个std::move是干嘛用的

二、为什么这里会报错?

另外,我在实际的开发过程中发现这个JUCE没法编译成一个单独的库的形式,而是只能以.cpp文件和.h文件导入引用的形式使用,如果有人知道如何编译成dll,可以和我交流。

探幽

一、这个std::move是干嘛用的

我们百度可以搜到,std::move是做了移动语义,什么是移动语义?它唯一的功能是将一个左值强制转化为右值引用,继而可以通过右值引用使用该值。那么什么是左值右值?还需要一步步娓娓道来。

左值右值

1.左值右值的概念

C++中左值(lvalue)和右值(rvalue)是比较基础的概念,虽然平常几乎用不到,但C++11之后变得十分重要,它是理解 move/forward 等新语义的基础。

  • 左值是可寻址的变量,有持久性;
  • 右值一般是不可寻址的常量,或在表达式求值过程中创建的无名临时对象,短暂性的。

左值和右值主要的区别之一是左值可以被修改,而右值不能。

可以参考如下一段代码:

int a, b; 	// a 为左值
a = 3; 		// 3 为右值
b = a + 3;  // a+3 为右值
b = a; 		// a是左值 

2.左值引用和右值引用

我们说到引用的时候,大部分都是在说左值引用

  • 左值引用:引用一个对象;
  • 右值引用:就是必须绑定到右值的引用,C++11中右值引用可以实现“移动语义”,通过 && 获得右值引用。

或者一般情况下,也就是绑定了一个会随着右值变化而变化的值,比如:

int x = 6; 		// x是左值,6是右值
int &y = x; 	// 左值引用,y引用x

int &z1 = x * 6; 			// 错误,x*6是一个右值
const int &z2 =  x * 6; 	// 正确,可以将一个const引用绑定到一个右值

int &&z3 = x * 6; 	// 正确,右值引用
int &&z4 = x; 		// 错误,x是一个左值

什么意思呢,我们可以写一段简单的代码来演示一下:

int main()
{
    int x = 114;
    int c = x * 2;
    int&& b = x * 2;
}

在上面这两段代码中,第二行和第三行的执行逻辑不一样。

当我们走到第二行的时候,实际上是做了:

  1. 创建了一个临时变量temp = x * 2
  2. 令c拷贝一份temp变量
  3. delete temp变量

但我们在第三行中则稍做了些改变

  1. 创建了一个临时变量temp = x * 2
  2. 令c变为指向 temp 变量 的引用

这样可以看到,如果使用右值引用的方式,则会直接省去一个拷贝操作的开销,相对的就少了拷贝的内存开销。

二、移动语义的概念解决了什么问题?

如果一个类中涉及到资源管理,用户必须显式提供拷贝构造、赋值运算符重载以及析构函数,否则编译器将会自动生成一个默认的,如果遇到拷贝对象或者对象之间相互赋值,就会出错,比如:

class String
{
public:
	String(char* str = "")
	{
		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就被销毁了,最后使用返回的临时对象构造s3,s3构造好之后,临时对象就被销毁了。仔细观察会发现:strRet、临时对象、s3每个对象创建后,都有自己独立的空间,而空间中存放内容也都相同,相当于创建了三个内容完
全相同的对象,对于空间是一种浪费,程序的效率也会降低,而且临时对象确实作用不是很大,那能否对该种情况进行优化呢?
C++11提出了移动语义概念,即:将一个对象中资源移动到另一个对象中的方式,可以有效缓解该问题。

我们看到 关于+号的函数如下:

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 strRet(pTemp);

这一句话如果我们不修改原有的这个String类的话,这一句话则是一个拷贝开销,我们都知道拷贝带来的开销是比较大的,所以我们需要解决这个问题。

则需要在其构造函数里面下手:

String(String&& s)
	: _str(s._str)
{
	s._str = nullptr;
}

因为strRet对象的生命周期在创建好临时对象后就结束了,即将亡值,C++11认为其为右值,在用strRet构造临时对象时,就会采用移动构造,即将strRet中资源转移到临时对象中。而临时对象也是右值,因此在用临时对象构造s3时,也采用移动构造,将临时对象中资源转移到s3中,整个过程,只需要创建一块堆内存即可,既省了空间,又大大提高程序运行的效率。

注意:

  1. 移动构造函数的参数千万不能设置成const类型的右值引用,因为资源无法转移而导致移动语义失效。
  2. 在C++11中,编译器会为类默认生成一个移动构造,该移动构造为浅拷贝,因此当类中涉及到资源管理时,用户必须显式定义自己的移动构造。

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

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

相关文章

Mybatis进阶2

Mybatis进阶1-CSDN博客 Mybatis入门-CSDN博客 Mybatis入门2-CSDN博客 我们接下来要学习Mybatis的高级查询 我们先在数据库中准备我们需要的数据表 teacher表 课程表:与教师表是一对多的关系,所以有一个外键字段 学生表 由于学生表和课程表是多对多的…

Android selinux权限

一.SE 概述 SELinux 是由美国NSA(国安局)和 SCC 开发的 Linux的一个扩张强制访问控制安全模块。原先是在Fluke上开发的,2000年以 GNU GPL 发布。从 fedora core 2开始, 2.6内核的版本都支持SELinux。 在 SELinux 出现之前&#…

智慧公厕打造公共厕所智慧化管理模式

智慧公厕如何打造智慧化的管理模式?随着智能科技的快速发展,智慧公厕成为了城市管理的一项重要工作。智慧公厕的智能化管理不仅可以提升公厕的整体管理水平,还能为市民提供更加便捷、舒适的使用体验。本文将以智慧公厕源头实力厂家广州中期科…

Qt QImageWriter类介绍

1.简介 QImageWriter 用于写入图像文件的类。它提供了将 QImage 对象保存到不同图像格式文件的功能,包括但不限于 PNG、JPEG、BMP 等。QImageWriter 可以将图像写入文件,也可以写入任何 QIODevice,如 QByteArray,这使得它非常灵活…

CGAL 网格简化

文章目录 一、简介二、实现代码三、实现效果参考资料一、简介 为了提高网格处理的效率,通常需要将过于冗长的3D数据集简化为更简洁而又真实的表示。尽管从几何压缩到逆向工程有许多应用,但简洁地捕捉表面的几何形状仍然是一项乏味的任务。CGAL中则为我们提供了一种通过变分几…

MSYS2 Pacman常用命令--以及实际中安装linux命令

MSYS2 Pacman常用命令--以及实际中安装linux命令: 有时候需要使用linux下的命令,用这个工具就是可以实现内容 虽然现在在windows下的wsl命令以及可以很好的使用linux了,但是MSYS2也是个不错的工具: 如何下载linux下nc&#xff0c…

Nodejs-内存控制(垃圾回收机制)(新生代老生代)(Scavenge算法)

内存控制 v8的垃圾回收机制和内存限制 对于性能敏感的服务器端程序,内存管理的好坏,垃圾回收状态的优良成都,都会对服务器造成影响 Node和V8 Node在JavaScript的执行上受益于v8,随着v8的升级享受到更好的性能和性的语言特征。…

详解基于 RAG 的 txt2sql 全过程

前文 本文使用通义千问大模型和 ChromaDB 向量数据库来实现一个完整的 text2sql 的项目,并基于实际的业务进行效果的展示。 准备 在进行项目之前需要准备下面主要的内容: python 环境通义千问 qwen-max 模型的 api-keyChromaDB 向量数据库acge_text_…

一款 NodeJS 版本管理工具 NVM (Windows)

一、简介 Node Version Manager(NVM)是一种用于管理多个 NodeJS 版本的工具。在日常工作中,我们可能同时在进行多个不同的项目开发,每个项目的需求不同,依赖与不同版本的NodeJS 运行环境。这种情况下,维护…

数据处理学习笔记9

一些其他的函数 “Resize”和“Reshape”的区别主要在于它们对数组元素数量和形状的处理方式不同,以下是详细介绍: “Resize”通常会改变数组的元素数量,在放大数组形状时会用0补全新增的元素,而在缩小数组形状时会丢弃多余的元素…

一款AI工作流项目:phidatahq/phidata

一款AI工作流项目:phidatahq/phidata 构建和测试功能强大的 AI 工作流程。该项目提供了一个工作流平台,可以结合大型语言模型(LLM)和各种工具,扩展模型的实用性和应用范围。[1][4][5] 开发各种 AI 助手应用,如客服聊天机器人、数据分析工具、研究助手等。phidata 提…

Golang | Leetcode Golang题解之第72题编辑距离

题目&#xff1a; 题解&#xff1a; func minDistance(word1 string, word2 string) int {m, n : len(word1), len(word2)dp : make([][]int, m1)for i : range dp {dp[i] make([]int, n1)}for i : 0; i < m1; i {dp[i][0] i // word1[i] 变成 word2[0], 删掉 word1[i], …

LabVIEW波浪发电平台浮筒取能效率数据采集系统

LabVIEW波浪发电平台浮筒取能效率数据采集系统 随着化石能源的逐渐减少以及能源价格的上升&#xff0c;寻找可替代的、可再生的、清洁的能源成为了世界各国的共识。波浪能作为一种重要的海洋能源&#xff0c;因其巨大的潜力和清洁性&#xff0c;近年来受到了广泛关注。开发了一…

32 OpenCV Harris角点检测

文章目录 cornerHarris 算子示例 角点检测 cornerHarris 算子 void cv::cornerHarris ( InputArray src,OutputArray dst,int blockSize,int ksize,double K,int borderType BORDER_DEFAULT) src:待检测Harris角点的输入图像&#xff0c;图像必须是CV 8U或者CV 32F的单通道…

玩comfyui踩过的坑之使用ComfyUI_Custom_NODES_ALEKPET翻译组件问题

环境&#xff1a; 秋叶安装包&#xff0c;安装ComfyUI_Custom_NODES_ALEKPET组件或者直接下载网盘中的包&#xff0c;直接解压包到comfyui根目录/custom_nodes/&#xff0c;重启后&#xff0c;按指导文件操作。 注意&#xff1a;网盘指导包中有配置好的流程json文件&#xff0…

【源码】 频裂变加群推广强制分享引流源码

视频裂变加群推广强制分享引流源码&#xff0c;用户达到观看次数后需要分享给好友或者群,好友必须点击推广链接后才会增加观看次数。 引导用户转发QV分享,达到快速裂变引流的效果&#xff01; 视频裂变推广程序&#xff0c;强制分享链接&#xff0c;引导用户转发&#xff0c;…

prometheus搭建

1.prometheus下载 下载地址:Download | Prometheus 请下载LTS稳定版本 本次prometheus搭建使用prometheus-2.37.1.linux-amd64.tar.gz版本 2.上传prometheus-2.37.1.linux-amd64.tar.gz至服务器/opt目录 CentOS7.9 使用命令rz -byE上传 3.解压缩prometheus-2.37.1.linux…

VscodeC/C++环境配置

引言 vscode是一款非常好用的编辑器&#xff0c;集成了大量的插件&#xff0c;具有很高的自由度&#xff0c;因此广受大家的喜爱。但是他本身是不带编译器的&#xff0c;因此如果要使用vscode来编译C/C程序的话&#xff0c;我们需要额外安装编译器并且为vscode配上环境。 编译…

Docker 入门与实践:从零开始构建容器化应用环境

Docker 一、docker常用命令docker ps 格式化输出Linux设置命令别名 二、数据卷相关命令挂载到默认目录&#xff08;/var/lib/docker&#xff09;挂载到本地目录 三、自定义镜像Dockerfile构建镜像的命令 四、网络自定义网络 五、DockerCompose相关命令 一、docker常用命令 dock…

Python | Leetcode Python题解之第71题简化路径

题目&#xff1a; 题解&#xff1a; class Solution:def simplifyPath(self, path: str) -> str:names path.split("/")stack list()for name in names:if name "..":if stack:stack.pop()elif name and name ! ".":stack.append(name)re…
最新文章