语言部分
1. Variadic Templates可变参数模板
可以设计不同个数,不同类型的参数模板。
详见Variadic Templates介绍
2. nullptr
nullptr 出现的目的是为了替代 NULL。
在某种意义上来说,传统 C++ 会把 NULL、0 视为同一种东西,这取决于编译器如何定义 NULL,有些编译器会将 NULL 定义为 ((void*)0),有些则会直接将其定义为 0。
nullptr 的类型为 nullptr_t,能够隐式的转换为任何指针或成员指针的类型,也能和他们进行相等或者不等的比较。
3. 类型推导
C++11 引入了auto
和 decltype
这两个关键字实现了类型推导,让编译器来操心变量的类型。
auto
使用 auto 进行类型推导的一个最为常见而且显著的例子就是迭代器。在以前我们需要这样来书写一个迭代器:
for(vector<int>::const_iterator itr = vec.cbegin(); itr != vec.cend(); ++itr);
而有了 auto 之后可以:
for(auto itr = vec.cbegin(); itr != vec.cend(); ++itr);
decltype
decltype 关键字是为了解决 auto 关键字只能对变量进行类型推导的缺陷而出现的。它的用法和 sizeof 很相似:
decltype(表达式)
在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值。
4. 基于范围的 for 循环
C++11 引入了基于范围的迭代写法,我们拥有了能够写出像 Python 一样简洁的循环语句。
最常用的 std::vector 遍历将从原来的样子:
std::vector<int> arr(5, 100);
for(std::vector<int>::iterator i = arr.begin(); i != arr.end(); ++i)
{
std::cout << *i << std::endl;
}
变得非常简单:
// & 启用了引用可以方便直接改值
for(auto &i : arr) {
std::cout << i << std::endl;
}
5.构造函数
委托构造,默认构造
C++11 引入了委托构造的概念,这使得构造函数可以在同一个类中一个构造函数调用另一个构造函数,从而达到简化代码的目的:
class Base
{
public:
int value1;
int value2;
Base ()=default;
Base(int a)
{
value1 = a;
}
Base(int b) : Base(int a) // 委托 Base(int a) 构造函数
{
value2 = b;
}
}
//一般自己 定义了构造函数编译器就不再生成默认的构造函数,=default;可以使编译器继续生成默认构造函数(基本造函数,拷贝构造函数,赋值函数=,析构函数)
//使用=delete;可以禁止编译器自动生成默认构造函数
6.Lambda 表达式
Lambda 表达式,实际上就是提供了一个类似匿名函数的特性,而匿名函数则是在需要一个函数,但是又不想费力去命名一个函数的情况下去使用的。类似于inline函数
Lambda 表达式的基本语法如下:
[ caputrue ] ( params ) mutable_opt -> retType { body; }
详见lambda表达式
7.类的继承中 虚函数重写关键词override,关键词final
class A
{ virtual void func(int){ } };
class B : A
{ void func(float) override{ } };
如果不加override,编译器认为A和B中的两个func是独立的两个函数(因为参数类型不同),如果B中func是想重写父类A中的func,加上override关键词告诉编译器是重写函数,编译器会报错
,因为重写函数参数类型要一致,所以如果主观上是要重写函数,最好加上override关键词,有助于编译器纠错。
在类的声明后面加final,表示该类不能被其他类再继承。在虚函数后面加final表示该虚函数在子类中不能再被重写。
class C final : A
{ void func(int) final override { } };
8. 常量表达式constexpr
9.Uniform Initialization 一致性初始化
可以统一的在变量后面用{}进行初始化。不需要‘=’。
vector v{1,2,4};
标准库部分
10.右值引用和move语义。
解决非必要的拷贝。
右值引用和move语义详解
11.新增容器
std::array
std::array 保存在栈内存中
,相比堆内存中的 std::vector,我们能够灵活的访问这里面的元素,从而获得更高的性能。
std::array 会在编译时创建一个固定大小的数组,std::array 不能够被隐式的转换成指针,使用 std::array只需指定其类型和大小即可
std::forward_list
std::forward_list 是一个列表容器,使用方法和 std::list 基本类似。
和 std::list 的双向链表的实现不同,std::forward_list 使用单向链表进行实现
,提供了 O(1) 复杂度的元素插入,不支持快速随机访问(这也是链表的特点),也是标准库容器中唯一一个不提供 size() 方法的容器
。当不需要双向迭代时,具有比 std::list 更高的空间利用率。
unordered container:
unordered_set, unordered_multiset, unordered_map, unordered_multimap.
其底部均由Hashtable类实现
。
12.tuple(利用Variadic Templates可变参数模板实现)
tuple属于标准库里stl以外的部分。
存放任意个不同类型的数据
tuple<int, float, string> t1{3, 4.4, "abc"};
或者:auto t1=make_tuple(3, 4.4, "abc");
取出第i个元素: get<i>(t1); i从0开始。 其返回的是引用,可以用来改变t1内的元素值(类似于索引)
。
将tuple内元素分解:
int a;
float b;
string c;
tie(a, b, c)=t1