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

news2024/9/24 23:30:41

一、问题

当我尝试在\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.coloradmin.cn/o/1644789.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OpenAI 也要做搜索?传 SearchGPT 将迎击谷歌核心业务!OpenAI 与金融时报新协议已定,将进行链接和引用

OpenAI也要杀入AI搜索领域分一杯羹?非常可能!毕竟连SearchGPT的入口已经准备好了! 图片 X平台上网友甚至还发现了SearchGPT的medo视频! OpenAI凭借自身的技术积累,如果真的进入搜索应用业务,必然…

震撼来袭!AI创新燃爆2024中关村论坛,唯迈医疗破解心脑血管“命门”危机

4月29日,备受瞩目的2024中关村论坛圆满闭幕。国内领先的介入诊疗全流程解决方案企业——唯迈医疗,携新一代Taikon太空 DSA和介入手术机器人惊艳亮相,以AI赋能介入诊疗,为心脑血管疾病治疗带来了革命性的突破,引发党央媒…

最新优质电商API接口,附带教程【多语言环境高并发】

给大家更新一波24年一月份的新接口吧。 01 接口信息 线路推荐: 多仓: 1.春盈: https://wds.ecsxs.com/230989.json 2.无意: http://www.wya6.cn/tv/yc.json 3.主流电商平台API数据采集 单仓: 1.饭太硬: http:/…

阿里实习生:面试阿里其实并没有那么难。

愉快的五一假期已经结束了, 又要投入到学习和工作当中了。 今天分享一位同学在阿里的Go后端实习面经详解, 希望对你有帮助。 Go里有哪些数据结构是并发安全的? 并发安全就是程序在并发的情况下执行的结果都是正确的; Go中数据类型分为两大类&#xff…

Altman确认:神秘Chatbot非GPT-4.5,OpenAI搜索引擎即将上线

🚀 Altman确认:神秘Chatbot非GPT-4.5,OpenAI搜索引擎即将上线 摘要:近日,Sam Altman在哈佛大学的演讲中确认,引发广泛猜测的gpt2-chatbot并非OpenAI即将发布的下一代模型GPT-4.5。与此同时,关于…

llama3 史上最强开源大模型,赶超GTP-4,逼宫OpenAI

2024年4月18日,Meta公司推出了开源大语言模型Llama系列的最新产品—Llama 3,包含了80亿参数的Llama 3 8B和700亿参数的Llama 3 70B两个版本。Meta称其为“迄今为止最强的开源大模型”。 怪兽级性能 LLaMA3 提供了不同参数规模的版本,以适应…

性能问题分析排查思路之机器(4)

前言 本文是性能问题分析排查思路的展开内容之一,主要分为日志1期,机器4期、环境2期共7篇系列文章,本期是第四篇,讲机器(硬件)的内存方面的分析排查方法与最佳实践。 在性能问题分析排查系列的位置如下图…

辐射传输基础理论详解与LST反演方法

地表温度LST(Land Surface Temperature)是区域和全球尺度上陆地表层系统过程的关键参数,它综合了地表与大气的相互作用以及大气和陆地之间能量交换的结果。地表温度作为众多基础学科和应用领域的一个关键参数,能 够提供地表能量平衡状态的时空变化信息&a…

C语言 | Leetcode C语言题解之第70题爬楼梯

题目: 题解: int climbStairs(int n) {double sqrt5 sqrt(5);double fibn pow((1 sqrt5) / 2, n 1) - pow((1 - sqrt5) / 2, n 1);return (int) round(fibn / sqrt5); }

8.11 矢量图层线要素单一符号使用一

文章目录 前言简单线(Simple line)符号的使用QGis中的使用二次开发代码实现 总结 前言 本章介绍矢量图层线要素单一符号中简单线(Simple line)的使用说明:文章中的示例代码均来自开源项目qgis_cpp_api_apps 简单线&a…

C++:map和set类

关联式容器 在初阶阶段,我们已经接触过STL中的部分容器,比如:vector、list、deque、 forward_list(C11)等,这些容器统称为序列式容器,因为其底层为线性序列的数据结构,里面 存储的是元素本身。那什么是关…

政安晨:【Keras机器学习示例演绎】(三十六)—— 用聚合注意力增强信念网络

目录 导言 设置和导入 超参数 加载 CIFAR10 数据集 增强层 卷积干 卷积主干 注意力汇集 Patch convnet 回调 学习率时间表 训练 推理 结论 政安晨的个人主页:政安晨 欢迎 👍点赞✍评论⭐收藏 收录专栏: TensorFlow与Keras机器学习实战 希望…

【吊打面试官系列】Java高并发篇 - Java 线程池中 submit() 和 execute()方法有什么区别?

大家好,我是锋哥。今天分享关于 【Java 线程池中 submit() 和 execute()方法有什么区别?】面试题,希望对大家有帮助; Java 线程池中 submit() 和 execute()方法有什么区别? 两个方法都可以向线程池提交任务&#xff0c…

Libcity笔记:原子文件

1 介绍 Libcity中的数据以原子文件的形式存在 2 原子文件类别 对于不同的交通预测任务,可能用到不同的原子文件,同一个数据集不一定包含全部六种原子文件 网格数据需要按照先行后列的顺序遍历OD数据需要按照先起点后终点的顺序遍历 2.1 geo 存储地理…

1-38 流资源类结构

一 简介 1. Java中所说的流资源--IO流 2.为什么学习留资源? --要操作文件中的数据 将数据写入指定的文件 将数据从指定的文件读取 3.分类 -- 四大基流 , 八大子流 (重点) 按照流向分 : 输入流 和输出流 按照操作数据资源的类型划分 字符流 (重点) Reader -- 字符…

前端 | iframe框架标签应用(二)| 外部页面导入

文章目录 📚实现效果📚模块实现解析🐇html🐇css🐇javascript 📚实现效果 点击右上角喇叭,弹出iframe页面框,链接bilibili白噪音视频页面;点击关闭按钮,关闭弹…

[力扣题解]102.二叉树的层序遍历

题目&#xff1a;102. 二叉树的层序遍历 代码 迭代法 class Solution { public:vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> que;TreeNode* cur;int i, size;vector<vector<int>> result;if(root ! NULL){que.push(ro…

百面算法工程师 | 目标检测网络总结——object detect

目录 5.1 Single Shot MultiBox Detector&#xff08;SSD&#xff09; 5.2 YOLO 5.2.1 v1 5.2.2 v2 5.2.3 v3 5.2.4 v4 5.2.5 v5 【后续出详细面试考点&#xff0c;订阅我的专栏&#xff0c;更新第一时间通知】 已更新&#xff1a; 百面算法工程师 | YOLOv5面试考点原理…

Redis-三主三从高可用集群搭建

正式搭建之前&#xff0c;注意事项&#xff08;坑&#xff09;提前放到最开始&#xff0c;也可以出问题回来看&#xff0c; &#xff08;1&#xff09;第二步中最好将配置文件中的logfile自定义一个目录&#xff0c;以便于在第五步中启动出错的时候迅速定位错误。 &#xff0…

羊毛项目(华为iPhone茅台),讲解抢购渠道与抢购注意事项

薅羊毛天花板&#xff0c;华为iPhone茅台无脑撸&#xff0c;几分钟换几百元(非脚本项目) 网盘自动获取 链接&#xff1a;https://pan.baidu.com/s/1lpzKPim76qettahxvxtjaQ?pwd0b8x 提取码&#xff1a;0b8x