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

news/2024/11/24 11:30:21/

👍作者主页:进击的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.ppmy.cn/news/1109063.html

相关文章

C#控制台程序中使用log4.net来输出日志

Apache log4net 库是一个帮助程序员将日志语句输出到各种输出目标的工具。log4net 是优秀的 Apache log4j™ 框架到 Microsoft .NE​​T 运行时的端口。 我喜欢他可以自定义输出&#xff0c;区分等级等特点。 导入库 我们在工程里添加NuGet的包。输入名称log4net &#xff0…

系统安全漏洞检测技术第三方检测机构

安全测试报告 建立一个安全的Web系统一直是很多企业的目标&#xff0c;一个比较实用的方法就是建立比较容易实现的相对安全的系统&#xff0c;同时按照一定的安全策略建立相应的安全辅助系统&#xff0c;系统安全漏洞检测就是这样一类安全辅助系统。 系统安全漏洞检测技术 1、…

Java项目---图片服务器

图片服务器--->服务器&#xff08;图床&#xff09; 核心功能&#xff1a;上传图片、展示图片等 比如&#xff1a;编写博客时我们会插入图片&#xff0c;本质上是往文章中放了一个链接&#xff08;URL&#xff09;&#xff0c;这个URL资源在另外一个服务器上。 核心知识点…

电动车彻底取代燃油车?瑞士限制,中国每天烧7辆,现实不乐观

随着新能源汽车在国内汽车市场的销量占比突破三成&#xff0c;业界对于电动汽车取代燃油车相当乐观&#xff0c;然而电动汽车存在的不少问题却不容忽视&#xff0c;这正逐渐成为电动汽车普及的巨大障碍。 电动汽车如今面临的问题不少&#xff0c;最让消费者吐槽的是充电问题&am…

Maven 和 Gradle 官方文档及相关资料的网址集合

文章目录 官方MavenGradle 笔者MavenGradle 官方 Maven Maven 仓库依赖包官方查询通道&#xff1a;https://mvnrepository.com/ Maven 插件官方文档&#xff1a;https://maven.apache.org/plugins/ 安卓依赖包官方查询通道*&#xff1a;https://maven.google.com/web/ Gra…

《动手学深度学习 Pytorch版》 4.10 实战Kaggle比赛:预测比赛

4.10.1 下载和缓存数据集 import hashlib import os import tarfile import zipfile import requests#save DATA_HUB dict() DATA_URL http://d2l-data.s3-accelerate.amazonaws.com/def download(name, cache_diros.path.join(.., data)): #save"""下载一个…

动手学深度学习——Windows下的环境安装流程(一步一步安装,图文并配)

目录 环境安装官网步骤图文版安装Miniconda下载包含本书全部代码的压缩包使用conda创建虚拟&#xff08;运行&#xff09;环境使用conda创建虚拟环境并安装本书需要的软件激活之前创建的环境打开Jupyter记事本 环境安装 文章参考来源&#xff1a;http://t.csdn.cn/tu8V8 官网…

目标检测YOLO实战应用案例100讲-基于小样本学习和空间约束的濒危动物目标检测(续)

目录 濒危动物图像空间约束算法 4.1 知识词典 4.2 空间约束算法 4.2.1 算法设计