C++进阶之C++11

news2024/9/22 9:57:42

个人主页:点我进入主页

专栏分类:C语言初阶  C语言进阶  数据结构初阶    Linux    C++初阶      算法   C++进阶

欢迎大家点赞,评论,收藏。

一起努力,一起奔赴大厂

目录

一.列表初始化

1.1一切皆可用列表初始化

1.2initializer list

二.声明

2.1auto

2.2decltype

2.3nullptr

三.左值和右值

3.1左值引用和右值引用

3.2 左值和右值比较

3.3右值引用场景(移动构造和移动赋值)

3.4完美转发与万能引用

3.5针对move一些补充

四.lambda表达式

4.1基本使用

4.2捕捉列表

五.新的类功能

六.可变参数模板

    6.1输出可变参数包的个数

 6.2使用

6.3emplace_back

七.包装器

        7.1function

                7.1.1基本用法

7.1.2一个应用场景

7.1.3使用类的成员函数的function

7.2bind


一.列表初始化

1.1一切皆可用列表初始化

        在C++11中出现了可以支持使用列表进行初始化,这是为了实现一切皆可用列表进行初始化,直接看代码:

class A
{
public:
	A(int a, int b)
		:_a(a)
		,_b(b)
	{}
private :
	int _a;
	int _b;
};
class B
{
public:
	B(int a)
		:_a(a)
	{}
private:
	int _a;
};
int main()
{
	int array[] = { 1,2,3,4 };

	//单参数隐式类型转化
	B b = { 1 };
	//多参数隐式类型转化
	A a = { 1,2 };
	A a1{ 2,3 };
	A* ptr = new A{ 1,2 };
	return 0;
}

1.2initializer list

        同时C++11支持initializer list对一些stl进行初始化,例如vector,

vector (initializer_list<value_type> il,
const allocator_type& alloc = allocator_type());allocator_type());

它可以直接用{}进行初始化,这个其实是initializer list的类型,我们看一下代码:

	vector<int> v = { 1,2,3,4 };

出现这种情况业主要是想完成一切皆可用{}初始化,由于不知道vetcor的参数的个数,所以采用这种方式。

二.声明

2.1auto

                在c++98中auto是一个存储类型的说明符,但是这玩意没什么用,所以就修改了它的用法,所以修改为了自动推导类型,看下面代码:

int main()
{
	int a = 1;
	auto b = 2;
	cout << typeid(b).name() << endl;
}

auto还可以作为返回值,看下面:

auto Add(int x, int y)
{
	return x + y;
}
int main()
{
	auto a = Add(1, 2);
	cout << typeid(a).name() << endl;
	return 0;
}

同样返回值是int。 

2.2decltype

        和auto类似,它作用于表达式上,直接上代码:

int main()
{
	double a = 1.1;
	double b = 2.2;
	decltype(a * b) c;
	decltype (a) d;
	cout << typeid(c).name() << endl;
	cout << typeid(d).name() << endl;
	return 0;
}

2.3nullptr

        由于在定义时将NULL定义为0,所以有时候会出现一些问题,所以新增添了一个nullptr,看一看源码:

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

三.左值和右值

        很多人有一个对左值和右值有一个误区那就是认为在等号左边是左值,右边是右值,其实这是不准确的,真正区分左值和右值是是否可以取地址,知道如何区分左值和右值重要吗?一点不重要,重要的是对左值和右值的引用。

3.1左值引用和右值引用

int main()
{
	//3个左值
	int a = 1;
	int* ptr = new int(1);
	const int b = 2;
	//对左值的引用
	int& c = a;
	int*& cptr = ptr;
	const int& d = b;
	return 0;
}

右值可以是一些匿名对象,常数,一些函数的返回值,其中对于自定义类型可以称为将亡值,看代码:

int Add(int x, int y)
{
	return x + y;
}
int main()
{
	int&& a = 1;
	int&& b = Add(1, 2);
	string&& s = string("1111");
	return 0;
}

3.2 左值和右值比较

        针对左值引用,左值引用不可以引用右值否则会报错,但是const属性的左值可以引用右值,

对于右值,右值引用不可以引用左值,但是可以引用move的左值,看代码:

int main()
{
	//int& a = 1; 左值引用=右值报错
	const int& ret1 = 1;//const左值引用=右值

	int a=1;
	//int&& ret=a; 右值引用=左值报错

	string s = "aaaaa";
	string&& ref2 = move(s);//右值引用=move左值
	return 0;
}

3.3右值引用场景(移动构造和移动赋值)

        在一些传参数时可以使用右值引用进行传参,右值引用可以大大减少数据的拷贝,例如在string的构造时我们可以使用右值进行构造也就是移动构造,在赋值构造时也让可以使用右值就是移动复制

//移动赋值
string& operator=(string&& s)
{
    cout << "string& operator=(string&& s) -- 移动语义" << endl;
    swap(s);
    return *this;
}
//移动构造
string(string&& s)
	:_str(nullptr)
{
	cout << "string(string&& s) -- 移动构造" << endl;
	swap(s);
}

3.4完美转发与万能引用

        完美转发是在函数模板模板中为了保持参数的原有属性设计的,看下面代码:

void Fun(int& x) { cout << "左值引用" << endl; }
void Fun(const int& x) { cout << "const 左值引用" << endl; }
void Fun(int&& x) { cout << "右值引用" << endl; }
void Fun(const int&& x) { cout << "const 右值引用" << endl; }
template<typename T>
void PerfectForward(T&& t)
{
	Fun(t);
}
int main()
{
	int a = 1;
	PerfectForward(a);//左值
	PerfectForward(1);//右值
	PerfectForward(move(a));//右值
	const int b = 2;
	PerfectForward(b);//const左值
	PerfectForward(move(b));//const右值
}

结果会和上面的一样吗?并不是,看结果:

这是为什么?这是由于左值还是左值,右值退化为了左值,此时的右值可以取地址了,如何解决呢?完美转发,将模板改为下面:

template<typename T>
void PerfectForward(T&& t)
{
	Fun(std::forward<T>(t));
}

上面的模板参数就是万能引用,&&不是指右值而是和T进行结合可以有左值也可以右值

3.5针对move一些补充

        一旦使用move他就认为这就是将亡值,会将这个值清空(内置类型不会清空),看下面代码:

int main()
{
	string s = "aaaaaa";
	string b = std::move(s);
}

四.lambda表达式

4.1基本使用

        对一个类进行升序排序需要写一个仿函数,看代码:

struct Goods
{
	string _name; // 名字
	double _price; // 价格
	int _evaluate; // 评价
	Goods(const char* str, double price, int evaluate)
		:_name(str)
		, _price(price)
		, _evaluate(evaluate)
	{}
};
struct GoodsPrice
{
	bool operator()(Goods& a, Goods& b)
	{
		return a._price < b._price;
	}
};
int main()
{
	vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
3 }, { "菠萝", 1.5, 4 } };
	sort(v.begin(), v.end(), GoodsPrice());
	return 0;
}

在使用lambda之前先看一下lambda的构成:

 其中返回值(->return-type)可以省略,当没有参数时可以省略参数,看下面表达式来进行升序:

sort(v.begin(), v.end(), [](Goods& a, Goods& b){
	return a._price < b._price;
});

实际上,lambda就相当于仿函数,当然也可以使用下面的方式进行排序:

auto swap = [](Goods& a, Goods& b) {
	return a._price < b._price;
	};
sort(v.begin(), v.end(), swap);

当有参数时可以这使用:

	int a = 1, int b = 2;
	auto add = [](int& a, int& b) {
		return a + b;
		};
	int c=add(a, b);

4.2捕捉列表

 先看样例:

int main()
{
	int a = 1, b = 2;
	auto swap = [a, b]()//mutable
		{
			int temp = a;
			a = b;
			b = temp;
		};
	swap();
	return 0;
}

这个代码会出现问题,它捕捉了a和b但是这两个时一个拷贝过来的,并且不可修改,当然加一个mutable可以修改,但是不会影响到外面的。因为时拷贝的。

当然给一个&表示引用就可以进行修改

int main()
{
	int a = 1, b = 2;
	auto swap = [&a, &b]()
		{
			int temp = a;
			a = b;
			b = temp;
		};
	swap();
	return 0;
}

五.新的类功能

        如果你没有自己实现移动构造函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。那么编译器会自动生成一个默认移动构造。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。
        如果你没有自己实现移动赋值重载函数,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个,那么编译器会自动生成一个默认移动赋值。默认生成的移动构造函数,对于内置类型成员会执行逐成员按字节拷贝,自定义类型成员,则需要看这个成员是否实现动赋值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。(默认移动赋值跟上面移动构造完全类似)
        如果你提供了移动构造或者移动赋值,编译器不会自动提供拷贝构造和拷贝赋值。

 还支持了可以让这些强制生成和强制不生产的关键字,default和delete

例如:

class Person
{
private :
	int _year;
	string _name;

public:
	Person(const char* name = "", int age = 0)
		:_name(name)
		, _year(age)
	{}
	Person(Person&&p) = default;//强制生成
	Person& operator=(Person&& p) = delete;//强制不生产
};

六.可变参数模板

    6.1输出可变参数包的个数

template< class ...Args>
void PrintArgs( Args&&... args)
{
	cout << sizeof(args) << endl;
}

注意不可以使用args[i]来进行访问。 

 6.2使用

template<class T>
void PrintArgs(T&& t)
{
	cout << t << endl;
}
template<class T,class ...Args>
void PrintArgs(T&& t,Args&&... args)
{
	cout << t << endl; 
	PrintArgs(args...);
}
int main()
{
	PrintArgs(1);
	PrintArgs(1, 1.1);
	PrintArgs(1, 1.1, "aaaa");
	return 0;
}

6.3emplace_back

        emplace_back相对于insert,push_back有很大优势,它时利用模板参数包进行构造,它直接传入类的参数,直接进行构造,当同时传入相同值时效率一样。尽量使用emplace_back.

七.包装器

        7.1function

                7.1.1基本用法

        直接看一段代码:

int f(int x, int y)
{
	return x + y;
}
struct F
{
	int operator()(int x, int y)
	{
		return x + y;
	}
};

int main()
{
    //函数
	function<int(int, int)> f1 = f;
	cout << f1(1,2)<<endl;
    
    //仿函数
	function<int(int, int)> f2 = F();
	cout << f2(1, 2) << endl;

    //lambda
	function<int(int, int)> f3 = [](int x, int y)
		{
			return x + y;
		};
	cout << f3(1, 2) << endl;
	return 0;
}

包装器function可以对函数,仿函数,lanmbda等进行包装,可以将他们组成一个类,看下面的验证:

template<class T,class K>
void Add(T t,K k)
{
	static int count = 0;
	cout << count++ <<  " "<<t(k) << endl;
};
double f(double x)
{
	return x / 1.1;
}
struct F
{
	double operator()(double x)
	{
		return x / 1.1;
	}
};

int main()
{

	Add(f, 3.3);
	Add(F(), 3.3);
	Add([](double x)
		{
			return x / 1.1;
		}, 3.3);
	/*function<double(double)> f1 = f;
	Add(f1, 3.3);

	function<double(double)> f2 = F();
	Add(f2, 3.3);

	function<double(double)> f3 = [](double x)
		{
			return x / 1.1;
		};
	Add(f3, 3.3);*/
	return 0;
}

当采用上半部分代码时结果为

这三个分别实例化一个函数,但是采用下半部分时,结果为

说明这三个就实例化了一个函数,包装器可以让他们称为同一个类型。

7.1.2一个应用场景

        将字符+,-,*,/利用map和他们对应的运算进行绑定,看代码:

int main()
{
	map<string, function<int(int, int)>> m = {
		{"+",[](int x,int y) {return x + y; }},
		{"-",[](int x,int y) {return x - y; }},
		{"*",[](int x,int y) {return x * y; }},
		{"/",[](int x,int y) {return x / y; }}
	};

	int a = 4, b = 2;
	cout << m["+"](a, b) << endl;
	cout << m["-"](a, b) << endl;
	cout << m["*"](a, b) << endl;
	cout << m["/"](a, b) << endl;
}

运行结果如下: 

7.1.3使用类的成员函数的function

        当成员函数是静态成员函数时,function的方式和其他的一样,当成员函数不是静态时,需要在参数哪里加上我们的this指针,=后写为&类域::成员函数,具体代码为:

class A
{
public:
	static void Count()
	{
		cout << count++ << endl;
	}
	void print(int x)
	{
		cout << num << endl;
	}
private:
	static int count;
	int num=10;
};
int A::count = 0;
int main()
{
	function<void()> f1 = A::Count;
	f1();

	function<void(A*, int)> f2 = &A::print;
	A a;
	f2(&a, 1);

	function<void(A, int)> f3 = &A::print;
	f3(A(), 1);
	return 0;
}

7.2bind

        bind是对函数参数进行绑定,它可以实现参数的呼唤也可以实现对一个参数进行绑定,看代码:

void F(const string& s, int x, int y)
{
	cout << s << "->血: " << x << " 蓝 " << y << endl;
}
int main()
{
	auto f1 = bind(F, "盖伦",placeholders::_1,placeholders::_2);
	f1(1, 1);
	return 0;
}

运行结果为:

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

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

相关文章

代码随想录 day 29 贪心

第八章 贪心算法 part03 134. 加油站 本题有点难度&#xff0c;不太好想&#xff0c;推荐大家熟悉一下方法二 https://programmercarl.com/0134.%E5%8A%A0%E6%B2%B9%E7%AB%99.html 135. 分发糖果 本题涉及到一个思想&#xff0c;就是想处理好一边再处理另一边&#xff0c;不…

MySQL基础操作全攻略:增删改查实用指南(上)

本节目标&#xff1a; CRUD : Create, Retrieve &#xff0c; Update &#xff0c; Delete 新增数据 查询数据 修改数据 删除数据 1. CRUD 注释&#xff1a;在 SQL 中可以使用 “-- 空格 描述 ” 来表示注释说明 CRUD 即增加(Create)、查询(Retrieve)、更新(Update)、…

什么是 IDR —— Linux 内核中的一种整数管理机制

文章目录 1 什么是 IDR1.1 IDR 的设计目的 2 IDR 的结构和实现2.1 核心数据结构2.2 常用操作2.2.1 分配 ID2.2.2 查找指针2.2.3 删除映射 2.3 IDR 的优点 3 Linux 内核中的整数 ID3.1 作用3.2 常见的整数 ID 示例 4 为什么要将整数 ID 与指针关联4.1 举例说明4.2 好处4.3 示例代…

学习笔记-Cookie、Session、JWT

目录 一、验证码的生成与校验 1. 创建生成验证码的工具类 2. 写一个 Controller 3. 实现验证码验证 1. 获取验证码 2. 验证码请求过程 3. 验证码的校验 4. 原理说明 5. 验证 6. 总结 二、JWT登录鉴权 1. 为什么要做登录鉴权&#xff1f; 2. 什么是 JWT 3. JWT相比…

MATLAB优化模型(2)

一、前言 在MATLAB中实现动态规划、图论、网络流模型&#xff08;如最短路、最大流、最小生成树&#xff09;的优化模型&#xff0c;可以通过多种方法完成&#xff0c;但通常会依赖于MATLAB内置的函数或工具箱&#xff0c;比如Optimization Toolbox、Graph Theory Toolbox等。以…

Python 实现股票指标计算——SKDJ

SKDJ (Stochastic KDJ) - 慢速随机指标 1 公式 LOWV:LLV(LOW,N); HIGHV:HHV(HIGH,N); RSV:EMA((CLOSE-LOWV)/(HIGHV-LOWV)*100,M); K:EMA(RSV,M); D:MA(K,M); 2 数据准备 我们以科创50指数 000688 为例&#xff0c;指数开始日期为2019-12-31&#xff0c;数据格式如下&#…

Leetcode 第 135 场双周赛题解

Leetcode 第 135 场双周赛题解 Leetcode 第 135 场双周赛题解题目1&#xff1a;3222. 求出硬币游戏的赢家思路代码复杂度分析 题目2&#xff1a;3223. 操作后字符串的最短长度思路代码复杂度分析 题目3&#xff1a;3224. 使差值相等的最少数组改动次数思路代码复杂度分析 题目4…

SQL注入 报错注入、文件上传、布尔盲注、时间盲注

第7关 文件上传 ---面试官常问 1、MySQL上传shell的满足条件 如果面试官问你如何通过MySQL向网站上传一个shell脚本或者其他语言的一些脚本 ---就可以通过outfile导出的方式进行上传&#xff1b; outfile导出的前提条件&#xff1a;1、必须知道网站的物理路径&#xf…

Java每日一练_模拟面试题2(循环依赖)

一、啥事Spring里面的循环依赖 SpringBoot 循环依赖通常发生在两个或多个Bean相互依赖对方时&#xff0c;例如&#xff1a;A依赖B&#xff0c;同时B也依赖A。 二、如何解决&#xff1f; 解决方案&#xff1a; 构造器注入&#xff1a;如果循环依赖发生在构造器中&#xff0c;S…

[YashanDB认证]YashanDB个人版安装

为什么选择YashanDB? 崖山数据库系统YashanDB是深圳计算科学研究院完全自主研发设计的新型数据库系统&#xff0c;经工信部下属机构权威检测&#xff0c;内核代码自主率100%。在经典数据库理论基础上&#xff0c;融入原创的有界计算理论、近似计算理论、并行可扩展理论和跨模融…

Taro学习记录(具体项目实践)

一、安装taro-cli 二、项目文件 三、项目搭建 1、Eslint配置 在项目生成的 .eslintrc 中进行配置 {"extends": ["taro/react"], //一个配置文件&#xff0c;可以被基础配置中的已启用的规则继承"parser": "babel/eslint-parser…

荒原之梦考研:专科考研成功的可能性大吗?

专科还是本科不是决定考研能否成功的关键因素&#xff0c;决定考研能否成功的关键因素是自己是否有清晰的规划、是否有足够的专注能力&#xff0c;以及是否能够吃得了考研的“苦”。 首先要有清晰的规划&#xff0c;比如说&#xff0c;不是我们每个人足够努力就都能考上 TOP1 …

electron-updater实现electron全量更新和增量更新——主进程部分

同学们可以私信我加入学习群&#xff01; 正文开始 前言更新功能所有文章汇总一、更新插件选择二、在main.js中引入我们的更新模块三、更新模块UpdateController.js暴露的方法checkUpdate四、更新模块UpdateController.js中的监听4.1监听是否有新版本需要更新&#xff1f;4.2 监…

红黑树与平衡二叉树的相同之处与不同之处

红黑树很多资料上写的非常繁杂&#xff0c;初次接触真的难以理解。写本文也就是为了记录一些思考和想法&#xff0c;并不会记录如何使用代码实现。 不记录代码还有个原因&#xff1a;黑红树的算法就是根据各种情况进行一些操作&#xff0c;情况很复杂&#xff0c;分插入的和删…

数据结构 二叉树和堆总结

树 概念 树是一种层次结构非线性的数据结构&#xff0c;其是由节点和边组成&#xff0c;可以用来表示层次关系的数据。 树的相关概念 节点&#xff1a;树的基本组成单位&#xff0c;每个节点都包含数据&#xff0c;同时与其他节点相互连接根节点&#xff1a;树的顶层节点&…

SpringBoot_第十一章(Thymeleaf模板引擎)

目录 1&#xff1a;什么是Thymeleaf模板引擎 2&#xff1a;springboot怎使用Thymeleaf 2.1&#xff1a;导入pom文件 2.2&#xff1a;查看ThymeleafAutoConfiguration 3&#xff1a;Thymeleaf核心语法 4&#xff1a;使用Thymeleaf 5&#xff1a;具体语法练习 1&#xff1a…

数据集划分方法

数据集划分是机器学习和数据科学中的一个重要步骤&#xff0c;主要目的是为了确保模型的有效性和可靠性。 留出法&#xff08;简单交叉验证&#xff09; 将数据集划分为互斥的子集&#xff1a;训练集和测试集。 训练集: 用于训练模型。 测试集: 用于评估模型的性能和验证其准确…

图神经网络揭秘:视觉和实用指南

目录 一、说明 二、图如何网络化&#xff1f; 三、你需要知道的 3.1 进入图神经网络 3.2 消息传递 3.3 我们如何处理最终的向量表示&#xff1f; 四、图神经网络&#xff0c;总结 4.1 为什么选择图形神经网络&#xff1f; 4.2 简而言之 一、说明 了解图神经网络的世界&#xff…

C#中投影运算的深入解析与实例应用

文章目录 1、投影运算的基本语法2、投影运算的高级用法3、投影运算在向量空间中的运用4、投影运算在数据库和XML中的实际应用5、投影运算能用于哪些实际场景&#xff1f;6、结论 在C#编程中&#xff0c;投影运算是一种常用的数据操作技术&#xff0c;它可以将一个数据集合转换成…

开放式耳机推荐?时尚潮流品牌:悠律ringbud pro开放式耳机实测测评

作为一位音乐发烧友&#xff0c;什么类型的耳机都体验过&#xff0c;有些几百上千的耳机音质还是差点意思&#xff0c;还是会有听久了感觉不舒服的情况&#xff0c;低音量感不够的问题&#xff0c;直到用了悠律ringbud pro开放式耳机&#xff0c;才算真正打开新世界的大门&…