【C++11】

1.列表初始化

C++98中,标准允许使用{}对结构体和数组进行初始化。C++11扩大了列表初始化的使用范围,使其可以用于所有的自定义类型和内置类型,使用初始化列表时,可添加等号(=),也可不添加,但是建议添加等号,这样可读性更高。

#include <iostream>
#include <vector>
#include <list>
#include <map>
int main()
{
	int a1 = 1;
	int a2(1);
	int a3 = { 1 };
	//不建议这样写,代码没有可读性
	int a4{ 1 };
	
	vector<int> v1 = { 1, 2 };
	list<double> lt = { 1.1, 1.3, 3.14 };
	map<int, int> countMap = { {1, 2}, {2, 3}, {3, 4} };

	return 0;
}

原因是C++11的STL容器中都加入了一个initializer list的构造函数
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
所以C++11中用{}括起来的列表叫做initializer list。
在这里插入图片描述
在这里插入图片描述
所以通过迭代器直接遍历整个initializer list ,就可以构造一段区间。

在这里插入图片描述
初始化列表中的pair类型为pair<const char*, const char*>,而countMap中pair的类型为pair<string, string>,两个类型不一致,怎么列表初始化呢
在这里插入图片描述
在这里插入图片描述
pair的构造和赋值是函数模板,只要类型可以转换就可以构造/赋值

2.声明

auto:自动推导类型,必须显示初始化,编译器将根据初始化的值自动推导类型

int main()
{
	map<string, string> countMap = { {"string", "字符串"}, {"sort", "排序"} };
	map<string, string>::iterator it1 = countMap.begin();
	auto it2 = countMap.begin();
	return 0;
}

decltype:将变量的类型声明为表达式指定的类型
在这里插入图片描述
nullptr:C++中NULL被定义为字面量0,就可能带来一些问题,所以新增了nullptr,用与表示空指针。

3.右值引用和移动语义

左值:变量,表达式或函数传引用返回
右值:字面量,表达式或函数的返回值
区别:
左值可以取地址,右值不能取地址
左值引用引用左值,但const左值引用可以引用右质
右值引用引用右值,但右值引用可以引用move之后的左值

引用的本质:减少拷贝
左值引用:
1.解决了自定义类型传参时的拷贝问题
2.解决了一部分返回对象拷贝问题(出了作用域,对象生命周期还在)
未解决问题:
返回临时对象的拷贝问题(出了作用域,对象的生命周期就到了,只能传值返回)

所以为了解决该问题,C++11提出了右值引用
C++11中把右值分为两类:
1.纯右值(内置类型右值)
2.将亡值(自定义类型右值)
同时C++11中的各个容器都新增了两个默认成员函数,移动构造和移动赋值。移动构造和移动赋值的本质是把自定义类型将亡值的资源进行转移,这样右值引用的移动语义解决了返回临时对象的拷贝问题。

移动构造:

  1. 我们不写,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个。编译器会自动生成一个默认移动构造。
  2. 默认生成的移动构造函数,对于内置类型成员进行值拷贝,自定义类型成员,则需要看这个成员是否实现移动构造,如果实现了就调用移动构造,没有实现就调用拷贝构造。
  3. 我们自己实现了,编译器就不会默认生成了

移动赋值

  1. 我们不写,且没有实现析构函数 、拷贝构造、拷贝赋值重载中的任意一个,那么编译器会自动生成一个默认移动赋值。
  2. 默认生成的移动构造函数,对于内置类型成员进行值拷贝,自定义类型成员,则需要看这个成员是否实现移动赋值,如果实现了就调用移动赋值,没有实现就调用拷贝赋值。
  3. 我们自己实现了,编译器就不会默认生成了

模板中的&&不代表右值引用,而是万能引用,其既能接收左值又能接收右值。 模板的万能引用提供了能够接收左值引用和右值引用的能力。
在这里插入图片描述
右值在被右值引用之后,右值的属性是左值,因为要实现移动构造和移动赋值的资源转移,所以右值在被右值引用之后,右值的属性是左值。
在这里插入图片描述

4.可变参数模板

在这里插入图片描述虽然可变参数模板在源代码级别看起来可能有些复杂,但它们在编译时会被完全展开,并由编译器处理,但这一展开过程对我们开说来说是不可见的。但是对于编译器来讲,就相当于传递了0到多个的参数而已。

5.lambda

ambda表达式书写格式:[] () mutable -> return_type { statement
}
ambda表达式各部分说明

  1. [] : 捕捉列表,该列表总是出现在lambda函数的开始位置,编译器根据[]来
    判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda函数使用。

[var]:表示值传递方式捕捉变量var
[=]:表示值传递方式捕获所有父作用域中的变量(包括this)
[&var]:表示引用传递捕捉变量var
[&]:表示引用传递捕捉所有父作用域中的变量(包括this)
[this]:表示值传递方式捕捉当前的this指针

  1. ():参数列表。与普通函数的参数列表一致,如果不需要参数传递,则可以
    连同()一起省略
  2. mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性。使用该修饰符时,参数列表不可省略(即使参数为空)。
  3. ->return_type:返回值类型。用追踪返回类型形式声明函数的返回值类型,没有返回值时此部分可省略。返回值类型明确情况下,也可省略,由编译器对返回类型进行推导。
  4. {statement}:函数体。在该函数体内,除了可以使用其参数外,还可以使用所有捕获到的变量。
    注意:
    在lambda函数定义中,参数列表和返回值类型都是可选部分,而捕捉列表和函数体可以为空。

在底层编译器对于lambda表达式的处理方式,完全就是按照函数对象的方式处理的,即:如果定义了一个lambda表达式,编译器会自动生成一个类,在该类中重载了operator()。

6.包装器

function包装器 也叫作适配器。C++中的function本质是一个类模板,也是一个包装器。可以包装任何可调用目标(包括普通函数、Lambda表达式、函数对象或绑定表达式等),并且可以用作函数的通用类型。这使得你能够将不同的可调用对象以统一的方式传递、存储和使用。

#include <functional>

int func(int x, int y)
{
	return x + y;
}

struct Sub
{

	int operator()(int x, int y)
	{
		return x - y;
	}
};

class X
{
public:
	static int mul(int x, int y)
	{
		return x * y;
	}
	int div(int x, int y)
	{
		return x / y;
	}
};

int main()
{
	function<int(int, int)> add = func;
	function<int(Sub*, int, int)> sub = &Sub::operator();
	function<int(int, int)> mul = X::mul;
	function<int(X*, int, int)> div = &X::div;

	Sub s;
	X x;

	cout << add(1, 2) << endl;
	cout << sub(&s, 1, 2) << endl;
	cout << mul(1, 2) << endl;
	cout << div(&x, 1, 2) << endl;
	return 0;
}

int main()
{
	//function<int(int, int)> add = func;
	//function<int(Sub*, int, int)> sub = &Sub::operator();
	//function<int(int, int)> mul = X::mul;
	//function<int(X*, int, int)> div = &X::div;

	//Sub s;
	//X x;

	//cout << add(1, 2) << endl;
	//cout << sub(&s, 1, 2) << endl;
	//cout << mul(1, 2) << endl;
	//cout << div(&x, 1, 2) << endl;

	Sub s;
	X x;
	//bind
	function<int(int, int)> add = func;
	//_1为函数的第一个参数,_2为第二个参数,以此类推
	function<int(int, int)> sub = bind(&Sub::operator(), &s, placeholders::_1, placeholders::_2);
	function<int(int, int)> mul = X::mul;
	function<int(int, int)> div = bind(&X::div, &x, placeholders::_1, placeholders::_2);
	return 0;
}
  • 13
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

LRBORRR

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值