【1++的C++进阶】之C++11(二)

news2024/11/29 11:41:53

👍作者主页:进击的1++
🤩 专栏链接:【1++的C++进阶】

文章目录

  • 一,类的新变化
  • 二,可变参数模板
  • 三,lambda表达式

一,类的新变化

在C++03之前,我们的默认成员函数有6个,我们在类与对象这篇中有过详细的讲解。C++11中又增加了两个默认成员函数—移动构造与移动赋值重载,其底层原理以及优势我们在上节已经有过描述。但是针对这两个默认成员函数,我们还需要注意以下说明:

  1. 如果你没有实现移动构造函数,并且也没有实现析构函数,拷贝构造,拷贝赋值重载中的任意一个,那么,编译器将会生成一个默认的移动构造函数,默认生成的移动构造对于内置类型成员,会进行逐字节的拷贝,对于自定义类型成员则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。移动赋值重载与移动构造此种情况类似。
  2. 如果你提供了移动构造或者移动赋值重载,那么编译器将不会再提供拷贝构造和拷贝赋值重载。

我们以以下代码为例:

class string
	{
	public:
		string(const char* str = "")
			:_str(nullptr)
		{
			cout << "string(const char* str)" << endl;
		}

		//拷贝构造
		string(const string& s)
			:_str(nullptr)
		{
			string tmp(s._str);
			std::swap(_str, tmp._str);
			//....
			cout << "string(const string& s)" << endl;
		}

		//移动构造
		string(string&& s)
		{
			std::swap(s._str, _str);
			cout << "string(string&& s)" << endl;

		}

		//赋值重载
		string& operator=(string& s)
		{

			std::swap(s._str, _str);
			cout << "string& operator=(string& s)" << endl;
			return *this;

		}

		//移动赋值
		string& operator=(string&& s)
		{
			std::swap(s._str, _str);
			return *this;
		}


	private:
		char* _str;
	};

	template<class T>
	class A
	{
	public:
		A(T&& s)
			:_a(0)
			,_s(std::forward<T>(s))
		{
			cout << "A" << endl;
		}
		
	A(T& s)
				:_a(0)
				, _s(s)
			{
				cout << "A" << endl;
			}
	private:
		int _a;
		T _s;
	};

	void test1()
	{
		hyp::string s2 = ("234");
		A<string> a3(s2);
		A<string> a4(move(a3));
	}

在这里插入图片描述

通过上述结果我们可以发现,对于自定义成员,其在没有自己实现析构函数,拷贝构造,赋值重载时,会自动调用自定义成员的移动构造。
当我们在类A中自己实现析构函数,拷贝构造,赋值重载任意一个时,结果如下:
在这里插入图片描述
其就不再自动调用自定义类型成员的移动构造,而是调用拷贝构造。
在这里插入图片描述
当我们添加A的移动构造后,编译器便不会再生成拷贝构造和赋值重载,而且我们也没有写,编译器便会报错。

C++11允许在类定义时给成员变量初始缺省值,默认生成构造函数会使用这些缺省值初始化。

强制生成默认函数的关键字default:
在这里插入图片描述
当有了移动构造后,便不会再生成拷贝构造,因此我们可以使用default当强制生成拷贝构造。

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

二,可变参数模板

C++11的新特性可变参数模板能够让我们创建可以接受可变参数的函数模板和类模板,相比C++98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进。然而由于可变模版参数比较抽象,使用起来需要一定的技巧。
我们在这里只进行简单的了解,下面我将演示两种能够获取到参数包中参数的方法。

方法一—递归

template<class T>
void Showlist(const T val)//递归终止条件
{
	cout << val << endl;
}

template<class T,class ...Args>
void Showlist(T val, Args... args)
{
	cout << val << " ";
	Showlist(args...);

}

方法二–逗号表达式

template<class T>
void printargs(T t)
{
	cout << t << " ";
}

template<class ...Args>
void Getargs(Args ...args)
{
	int arr[] = { (printargs(args),0)... };
}

在这里插入图片描述
在这里插入图片描述

三,lambda表达式

为什么要有lambda表达式?
假设我们现在需要对一个集合进行排序,(我们用std::sort进行排序)当我们要排升序时则需要传一个升序规则的仿函数,要降序时,则传一个降序规则的仿函数,当要元素类型不同时,则又需要该这个仿函数。比较麻烦,而lambda表达式可以避免这个麻烦,因此在C++11中就有了lambda表达式的出现。

lambda表达式的格式:
[捕捉列表] (参数列表) mutable -> 返回值类型 { 函数体}。

捕捉列表: 该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。
参数列表: 与普通函数的参数列表一致,如果不需要参数传递,则可以
连同()一起省略。
mutable: 默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。
返回值类型: 用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。
函数体: 在该函数体内,除了可以使用其参数外,还可以使用所有捕获
到的变量。

我们来小总结一下:在lambda表达式中,参数列表,返回值类型,mutable是可以选择的。因此我们就有了一个最简单的lambda表达式:[ ]{}。但该lambda表达式不能做任何事情。

关于捕获列表:
捕捉列表描述了上下文中哪些变量能够被lambda,是传值使用还是引用使用。
[var]:表示值传递方式捕捉变量var
[=]:表示值传递方式捕获所有父作用域中的变量(包括this)
[&var]:表示引用传递捕捉变量var
[&]:表示引用传递捕捉所有父作用域中的变量(包括this)
[this]:表示值传递方式捕捉当前的this指针

在这里插入图片描述
lambda表达式之间是不能够相互赋值的,但是可以进行拷贝构造,可以将其赋值给一个相同类型的函数指针。
在这里插入图片描述
在这里插入图片描述
明明是一样的两个lambda表达式,为什么却显式不能赋值呢?
我们会在后面进行说明。

可以像函数一样使用的对象有三种:函数指针;仿函数,又叫函数对象;lambda表达式。

我们以以下代码为例:

void test5()
{
	int val = 5;
	Test t(val);
	t(val);
	auto ret = [=](int tt) {return tt + val; };
	ret(val);
	cout << ret(val) << endl;
	cout << t(val) << endl;

}

在这里插入图片描述
我们再观察其汇编代码。
在这里插入图片描述
通过观察我们发现仿函数先是会调用其构造函数,构造出一个对象。
lambda表达式也通过捕获列表将捕获到的值用于初始化会,构造出一个对象。每一个lambda构造出的对象都是不同的,因此其看似两个相同的lambda,却不能够赋值。
在这里插入图片描述
在这里插入图片描述
并且,接下来他们都调用了operator()!!!!
因此实际在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理的,即:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator()。

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

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

相关文章

(2596. 检查骑士巡视方案leetcode,经典深搜)-------------------Java实现

&#xff08;2596. 检查骑士巡视方案leetcode,经典深搜&#xff09;-------------------Java实现 题目表述 骑士在一张 n x n 的棋盘上巡视。在 有效 的巡视方案中&#xff0c;骑士会从棋盘的 左上角 出发&#xff0c;并且访问棋盘上的每个格子 恰好一次 。 给你一个 n x n …

PY32F003F18之定时器中断

PY32F003F18定时器有TIM1&#xff0c;TIM3&#xff0c;TIM14&#xff0c;TIM16和TIM17。其中TIM1为高级定时器&#xff0c;其它为通用定时器。见下表&#xff1a; 一、PY32F003F18定时器的工作模式&#xff1a; 1、边沿对齐模式 计数器工作在"边沿对齐模式" 设置&q…

《动手学深度学习 Pytorch版》 4.7 前向传播、反向传播和计算图

4.7.1 前向传播 整节理论&#xff0c;详见书本。 4.7.2 前向传播计算图 整节理论&#xff0c;详见书本。 4.7.3 反向传播 整节理论&#xff0c;详见书本。 4.7.4 训练神经网络 整节理论&#xff0c;详见书本。 练习 &#xff08;1&#xff09;假设一些标量函数 X X X…

Wireshark把DDoS照原形

1 前言 MTU、 传输速度、 拥塞控制&#xff0c;还是各种重传&#xff0c;TCP传输相关的核心概念&#xff1a; 学习了RFC规范和具体的Linux实现通过案例&#xff0c;把这些知识灵活运用了起来 这种种还是在协议规范这大框架内的讨论&#xff0c;默认前提就是通信两端是遵照TC…

Activating More Pixels in Image Super-Resolution Transformer(HAT)超分

摘要 基于Transformer的方法在低级视觉任务&#xff08;如图像超分辨率&#xff09;上表现出令人印象深刻的性能。然而&#xff0c;我们发现这些网络只能通过归因分析利用有限的输入信息空间范围。这意味着Transformer的潜力在现有网络中仍未得到充分利用。为了激活更多输入像…

yolov7添加 iRMB模块

复制过来 yolo.py添加 yaml文件随便换&#xff0c;建议换3x3的 pip install timm0.6.5&#xff0c;版本问题记得搞一下

DNG格式详解,DNG是什么?为何DNG可以取代RAW统一单反相机、苹果安卓移动端相机拍摄输出原始图像数据标准

返回图像处理总目录&#xff1a;《JavaCV图像处理合集总目录》 前言 在DNG格式发布之前&#xff0c;我们先了解一下之前单反相机、苹果和安卓移动端相机拍照输出未经处理的原始图像格式是什么&#xff1f; RAW 什么是RAW&#xff1f; RAW是未经处理、也未经压缩的格式。可以…

基于开源模型搭建实时人脸识别系统(六):人脸识别(人脸特征提取)

文章目录 人脸识别的几个发展阶段基于深度学习的人脸识别技术的流程闭集和开集&#xff08;Open set&#xff09;识别人脸识别的损失Insightface人脸识别数据集模型选型参考文献结语人脸识别系统项目源码 前面我们讲过了人脸检测、人脸质量、人脸关键点、人脸跟踪&#xff0c;接…

微分中值定理

目录 费马定理 罗尔定理 拉格朗日中值定理 柯西中值定理 几个常用的泰勒公式 微分中值定理是微积分中的一个重要定理&#xff0c;它用于描述一个函数在某个区间内的平均变化率与该区间内某一点的瞬时变化率之间的关系。微分中值定理有两个主要形式&#xff1a;拉格朗日中值…

Kotlin Files Paths write ByteArray writeString写多行BufferedWriter

Kotlin Files Paths write ByteArray writeString写多行BufferedWriter import java.nio.file.Files import java.nio.file.Paths import java.nio.file.StandardOpenOptionfun main(args: Array<String>) {val filePath "./myfile.txt"val path Paths.get(…

【报错】springboot3启动报错

报错内容&#xff1a;Cannot load driver class: org.h2.Driver Error starting ApplicationContext. To display the condition evaluation report re-run your application with debug enabled. 解决; 通过源码分析&#xff0c;druid-spring-boot-3-starter目前最新版本是1…

微信小程序 写一个接口不会掉就不会停止的加载动画

我们可以在接口调用前执行 wx.showLoading({title: 加载中,mask: true })这个加载会在这一直转 显示这加载的动画 它不会自己停下来 而是需要你执行 wx.hideLoading()之后 这个加载动画才会停止 那么我们完全可以将wx.hideLoading()放在接口返回的回调中 这样 就达到了一个 …

LeetCode每日一题:2596. 检查骑士巡视方案(2023.9.13 C++)

目录 2596. 检查骑士巡视方案 题目描述&#xff1a; 实现代码与解析&#xff1a; bfs模拟 原理思路&#xff1a; 2596. 检查骑士巡视方案 题目描述&#xff1a; 骑士在一张 n x n 的棋盘上巡视。在有效的巡视方案中&#xff0c;骑士会从棋盘的 左上角 出发&#xff0c;并…

利用Semaphore实现多线程调用接口A且限制接口A的每秒QPS为10

前段时间在群里面发现有个群友抛出一个实际需求&#xff1a;需要通过一个接口拉取数据&#xff0c;这个接口有每秒10QPS限制&#xff0c;请问如何实现数据拉去效率最大化且限制调用拉取接口每秒10PQPS&#xff1f;我觉得这个需求挺有意思的&#xff0c;跟某群友讨论&#xff0c…

CopyOnWriteArrayList源码分析

其中唯一的线程安全 List 实现就是 CopyOnWriteArrayList。 特点 由于读取操作不会对原有数据进行修改&#xff0c;因此&#xff0c;对于每次读取都进行加锁其实是一种资源浪费。相比之下&#xff0c;我们应该允许多个线程同时访问 List 的内部数据&#xff0c;毕竟对于读取操…

企业邮箱选择指南:最适合跨境贸易的解决方案推荐

随着全球贸易的不断发展&#xff0c;外贸公司越来越依赖高效的沟通和协作工具。在众多企业邮箱选择中&#xff0c;哪一种最适合外贸公司的需求呢&#xff1f;让我们一起来看看外贸公司常用的企业邮箱解决方案。 对于外贸公司而言&#xff0c;可靠性是选择企业邮箱的首要考虑因…

LC1798. 你能构造出连续值的最大数目(JAVA)

LC1798. 你能构造出连续值的最大数目 题目描述贪心算法代码演示 题目描述 难度 - 中等 Leetcode - 1798. 你能构造出连续值的最大数目 给你一个长度为 n 的整数数组 coins &#xff0c;它代表你拥有的 n 个硬币。第 i 个硬币的值为 coins[i] 。如果你从这些硬币中选出一部分硬币…

前端构建工具 webpack 笔记

1、了解 webpack 1、定义&#xff1a;本质上&#xff0c;webpack 是一个用于现代 JavaScript 应用程序的静态模块打包工具&#xff0c;当 webpack 处理应用它会在内部从一个或多个入口点构建一个依赖图(dependency graph)&#xff0c;然后将你项目中所程序时&#xff0c;需的…

YOLO物体检测系列3:YOLOV3改进解读

&#x1f388;&#x1f388;&#x1f388;YOLO 系列教程 总目录 YOLOV1整体解读 YOLOV2整体解读 YOLOV3提出论文&#xff1a;《Yolov3: An incremental improvement》 1、YOLOV3改进 这张图讲道理真的过分了&#xff01;&#xff01;&#xff01;我不是针对谁&#xff0c;在…

《C++ Primer》第3章 字符串、向量和数组(二)

参考资料&#xff1a; 《C Primer》第5版《C Primer 习题集》第5版 3.3 标准库类型vector&#xff08;P86&#xff09; vector 表示对象的序列&#xff0c;其中所有对象的类型相同&#xff0c;每个对象都有一个与之对应的索引。vector 容纳着其他对象&#xff0c;所以常被称…