目录
一、C++11简介
二、列表初始化
1.引入
2.使用
2.1 内置类型与容器
2.2 自定义类型
3.原理
三、声明
四、新增STL容器
1.array(静态数组)
2.forward_list(单链表)
五、lambda表达式
1.lambda表达式的构成与规则
2.应用
3.lambda的底层原理
一、C++11简介
C++11更像是一种从C++98/03中孕育出来的一种新的语言,C++11能更好的用于系统开发和库开发,语法更加泛化和简单化,更稳定安全,不仅功能强大,而且能提高程序员的开发效率。
二、列表初始化
1.引入
C++11扩大了用大括号括起来的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可以添加(=),也可以不添加。
2.使用
2.1 内置类型与容器
//内置类型初始化
int x1 = { 10 };
int x2{ 20 };//省略赋值符号
int x3{ 10 + 20 };
//数组
int arr1[5]{ 1,2,3 };//后面也默认为0
int arr2[]{ 1,2,3,4,5 };
//动态数组
int* arr3 = new int[5] {1, 2, 3, 4, 5};
//标准容器
vector<int> v1{ 1,2,3,4 };
v1 = { 4,5,6,7 };//支持赋值
map<int, int> m{ {1,1},{2,2},{3,3},make_pair(4,4) };
2.2 自定义类型
struct point
{int _x;int _y;point(int x, int y):_x(x),_y(y){printf("调用了构造函数\n");}
};
point pp{ 2,2 };
point* ptr = new point[2]{ {1,1},{2,2} };
//当没有构造函数时会兼容C语言的特性,当有构造函数时会调用构造函数
3.原理
统一初始化列表({})是一个initializer_list类型,在很多STL容器中,都提供了一个支持initializer_list类型构造函数:
在对操作符=进行重载的时候,也会有该类型对应的函数:
三、声明(decltype)
声明其实一共包括两部分,分别是auto自动推导类型,以及decltype自动推导类型+定义对象。auto在之前的章节里已经详细讲过,这里不多进行赘述。
int func(int a)
{return a;
}
int main()
{int x;double y = 2.2;decltype(x) z = 2;//讲z定义成和x一样的类型decltype(&x) p;//定义一个指针类型int(*pfunc1)(int) = func;//定义一个函数指针类型pfunc1指向funcdecltype(&func) pfunc3 = func;auto pfunc4 = func;//函数指针使用起来也非常方便,不过这里使用auto进行推导更加便捷//在vector定义类型的时候auto无法使用,decltype可以很好的帮助定义类型vector<int> v;vector<int>::iterator it = v.begin();vector<decltype(it)> vv;//这里可以使用decltype,但是无法使用autovv.push_back(it);return 0;
}
注意decltype在推导函数指针类型的时候,需要加&符号。而不能将函数名就当做地址了。
四、新增STL容器
STL中新增加了一些容器,比如unordered_map和unordered_set等,还为这些容器增加了一些接口,比如列表的初始化,右值引用版本提高效率等。
1.array(静态数组)
int a1[10];
array<int, 10> a2;
array<int, 10>::iterator it = a2.begin();
array相较于直接定义数组而言,引入了迭代器更好的兼容了STL的用法,并且由对越界的检测,因为它的底层是函数调用。
2.forward_list(单链表)
对于已经有了带头双向循环链表list来说,forward_list显得更加的鸡肋,它不支持头插头删(因为需要遍历到最后影响效率),当定点插入的时候会插入在元素的后面。(因为插入到前面需要再定义一个指向前一个节点的指针)
五、lambda表达式
1.lambda表达式的构成与规则
[capture-list] (parameters)mutable->return->type{statement}
1.[capture-list]:捕捉列表,该列表出现在lambda的初始位置,编译器根据[]来判断带来的代码是否是lambda表达式,捕捉列表能够捕捉上下文中的变量供lambda使用。其实只能捕获上文中的数据。
[var]:表示获取某一个变量
[=]: 获取上文的所有变量
[&var]: 获取某一个变量的引用
[&]:获取上文变量的所有引用
2.(parameters): 参数列表,与普通函数的列表一致,如果不需要参数列表的话,可以连同()一起省略。
3.mutable:默认情况下,lambda函数总是一个const函数,mutable可以取消其常量性,使用改修饰符时,参数列表不可省略。
4.->return-type:返回值类型,用追踪返回形式声明函数的返回值类型,没有返回值(void)的时候可以将此部分省略。当返回值明确的情况下,也可以省略,由编译器对返回类型进行推导。
5.{statement}: 函数体,和普通函数使用方法相同。
可以把它理解成一个匿名函数。注意,它知识一个函数定义,真正想要使用函数需要进行函数调用。
2.应用
auto fun = [] {};//最简单lambda表达式
auto add1 = [](int a, int b)->int {return a + b; };
auto add2 = [](int a, int b) {return a + b; };//省略返回值,让编译器自动推导
cout << add1(1, 2) << endl;//和函数的调用方法相同
cout << add2(2, 3) << endl;
auto func = [] {cout << "hello lambda" << endl; };//没有参数
func();
int a = 10;
int b = 20;auto swap1 = [](int& x, int& y)//和函数一样交换数据的时候必须带引用{int z = x;x = y;y = z;};
swap1(a, b);
cout << a << " " << b << endl;
注意,如果lambda表达式在全局中,就算有上文数据的话,捕捉列表也必须为空。
3.lambda的底层原理
用一段最简单的代码为例:
auto func = [] {cout << "hello lambda" << endl; };//没有参数
func();
cout << typeid(func).name() << endl;
可以使用typeid类的name方法来查看一下lambda表达式的类型:
我们发现它的类型是一个类,其中<>中的长字符串是一个uuid,它是给编译器使用的,而不是给程序员使用的,经过一定的算法保证所有生成的uuid是不同的。
同时我们可以看一下汇编程序:
可以看到,调用lambda表达式其实就是调用该类的operator>()仿函数。