C++11新特性
auto
- 自动类型推导
1 | std::vector<std::string> vec; |
- 定义模板函数时,推到依赖模板函数的变量类型
1 | template<_typename _Tx, _typename _Ty> |
- 返回值
1 | auto multipy(_Tx x, _Ty y)->decltype(x * y) |
- 其他
1 | auto a=10,b=11.0;//报错,初始化必须统一类型 |
1 | int a=1; |
1 | int arr[3] = {1, 2, 3}; |
decltype
从变量或者表达式获取类型
1 | int var; |
1 | decltype(var);//int |
对于
decltype
所用的引用来说,如果变量名加上了一对括号,则得到的类型与不加括号时会有所不同。如果decltype
使用的是一个不加括号的变量,则得到的结果就是该变量的类型;如果给变量加上了一层或多层括号,编译器就会把它当成是一个表达式。
C++14可以使用不带尾随返回类型的 decltype(auto)
来声明其返回类型取决于其模板参数类型的模板函数。
1 | template<typename T, typename U> |
using
- 命名空间
1 | using namespace std; |
- 定义别名,类似
typedef
1 | using itType=std::vector<std::string>::iterator; |
using与typedef的差别是 using可以用于模板部分具体化,但是typedef不能
1 | template<class T> |
- 当一个派生类私有继承基类时,基类的public和protected数据成员在派生类中是private的形式,如果想让这些继承而来的数据成员作为public或者protected成员,可以用using来重新声明。using声明语句中名字的访问权限由该using声明语句之前的访问说明符决定。
1 | class Basic{ |
- 关于重写重载函数
1 | class A1 |
nullptr
nullptr
比0更安全
枚举作用域
1 | enum EnumA |
所以我们需要设置枚举的作用域,这样才可以编译的过
1 | enum class EnumA |
Lambda
其实lambda实现的方法是创建一个简略的类。**这个类重载了operator()**,所以表现的像个普通函数。一个lambda函数是这个类的实例。当这个类构造的时候,所有捕获的变量被传送到类中并保存为成员变量。
表达式
1 | [capture](parameters)->return-type{body} |
几个例子
1 | [](int x, int y) { return x + y; } // 隐式返回类型 |
- 关于
[]
的捕获信息
1 | [] //未定义变量.试图在Lambda内使用任何外部变量都是错误的. |
示例
1 | A1* a1=new A1(); |
explicit
显式转换,禁止单参数构造函数导致的自动转换
1 | class plebe |
default,delete
- default
4类特殊函数可以用default,即默认构造函数、析构函数、拷贝构造函数以及拷贝赋值运算符
特殊情况,如果类内有指针成员,特殊函数都用default,以下情况会导致错误
1 | class testA |
- delete
类内成员初始化
1 | class se |
右值引用
- 左值、右值
在C++11中可以取地址的、有名字的就是左值,反之,不能取地址的、没有名字的就是右值(将亡值或纯右值)
- 右值、将亡值
C++98中右值是纯右值,纯右值指的是临时变量值、不跟对象关联的字面量值。
将亡值则是C++11新增的跟右值引用相关的表达式,这样表达式通常是将要被移动的对象(移为他用),比如返回右值引用T&&的函数返回值、std::move的返回值,或者转换为T&&的类型转换函数的返回值。
- 左值引用、右值引用
- 左值引用就是对一个左值进行引用的类型。右值引用就是对一个右值进行引用的类型,事实上,由于右值通常不具有名字,我们也只能通过引用的方式找到它的存在
- 右值引用和左值引用都是属于引用类型。无论是声明一个左值引用还是右值引用,都必须立即进行初始化
- 引用类型本身自己并不拥有所绑定对象的内存,只是该对象的一个别名。左值引用是具名变量值的别名,而右值引用则是不具名(匿名)变量的别名。
1 | //int &a =2;//左值引用绑定右值,fail |
智能指针
智能指针是用对象去管理一个资源指针,同时用一个计数器计算引用当前指针对象的个数,当管理指针的对象增加或减少时,计数器也相应加1或减1,当最后一个指针管理对象销毁时,计数器为1,此时在销毁指针管理对象的同时,也对指针管理对象所管理的指针进行delete操作。
- shared_ptr
std::shared_ptr包装了new操作符动态分配的内存,可以自由拷贝复制,基本上是使用最多的一个智能指针类型。
注意事项
我们尽量使用shared_ptr构造函数或者make_shared的方式创建shared_ptr,禁止使用裸指针赋值的方式,这样会shared_ptr难于管理指针的生命周期。
1 | // 使用裸指针赋值构造,不推荐,裸指针被释放后,shared_ptr就野了,不能完全控制裸指针的生命周期,失去了智能指针价值 |
禁止使用指向shared_ptr的裸指针,也就是智能指针的指针,使用shared_ptr的指针指向一个shared_ptr时,引用计数并不会加一,操作shared_ptr的指针很容易就发生野指针异常。
1 | shared_ptr<int>sp = make_shared<int>(10); |
- weak_ptr
与std::shared_ptr最大的差别是在赋值的时候,不会引起智能指针计数增加。
1 | class A { |
weak_ptr的一些用法
1 | weak_ptr<T> w; //空weak_ptr可以指向类型为T的对象 |
- unique_ptr
unique_ptr是auto_ptr的继承者,对于同一块内存只能有一个持有者,而unique_ptr和auto_ptr唯一区别就是unique_ptr不允许赋值操作,也就是不能放在等号的右边(函数的参数和返回值例外),这一定程度避免了一些误操作导致指针所有权转移,然而,unique_str依然有提供所有权转移的方法move,调用move后,原unique_ptr就会失效
1 | unique_ptr<int> p1=make_unique<int>(11); |
模板和STL方面的修改
基于范围的for循环
1 | double price[5]={1.1,2.2,3.3,4.4,5.5}; |
新的STL容器
C++11新增的容器:forward_list,unordered_map,unordered_multimap,unordered_set,unordered_multiset
- 关于unordered_map与map
两者的接口差不多,基本可以互换。
一般来说unordered_map的综合性能比map要好,因此,通常我们可以使用unorderd_map代替map。
以下情况推荐使用map:
关键字类型的hash函数设计的很差, 或者==运算符的性能极差, 导致hash过程太耗时;
对内存使用有严格要求, 不能接受存储hash table的额外内存开销;
元素要求按顺序存储, 或者常常需要关联访问一个元素的上一个/下一个元素, 或者需要遍历整个map。
新的STL方法
新增了STL方法cbegin()
和cend()
,这些方法也返回一个迭代器,指向容器的第一个元素和最后一个元素的后面,因此可以用于指定包含全部元素的区间;这些新方法将元素视为const。类似的,crbegin()和crend()是rbegin()和rend()的const版本
valarray升级
C++11添加了两个函数begin()和end(),都接受valarray作为参数并且返回迭代器
摒弃export
C++98增加了关键字export,C++11摒弃了这个特性但是保留了关键字export
尖括号
为了避免与运算符>>混淆,C++要求在申明嵌套模板时使用空格将尖括号分开
1 | vector<list<int>> vl;//C++11开始不再强求空格 |