C++11的新特性介绍
一、auto无法带走cv限制符
在C++标准中,const和volatile被称为“cv限制符,cv-qualifier”,它们分别代表了变量的两种不同的属性“不变的”和“易变的”。C++11标准规定auto可以和cv限制符一起使用,但是声明为auto的变量不能从其初始化表达式中“带走”cv限制符。例如const auto a = 1; 如果我们声明auto b = a; 那么b的类型是int而非const int,这里的例外是引用和指针,如果我们声明auto & c = a; 那么c的类型是const int&,声明为引用的变量依然保持着与其引用的对象相同的属性。
相比之下,decltype则可以带走cv限制符,但如果是一个对象的定义中含有const或volatile限制符,使用decltype进行推导时,其成员不会继承const和volatile。举例说明,const int i=0; 那么decltype(i)是const int,而如果:
struct S { int i; };
const S a = {0};
那么decltype(a)的类型是const S,但是a.i的类型并不是const。
还需要注意的是类型定义时的冗余符号:
int *a;
auto * b = a;,这里b的类型是int *而不是int **,因为在auto声明中,*也可以是冗余的,而如果使用decltype:
decltype(a) *c = &a;//decltype(a) *c = a无法通过编译
c的类型是int **。
二、追踪返回类型
如果一个函数模板的返回类型依赖于实际的入口参数类型,那么该返回类型在模板实例化之前可能都无法确定,这样的话我们在定义该函数模板时就会遇到麻烦。你可能会想到使用decltype来解决下面这个问题:
template decltype(t1+t2) Sum(T1 &t1, T2 &t2) { return t1 + t2; }
这里的问题是显而易见的,编译期通常并不能预知未来,在推导decltype(t1+t2)的时候,t1和t2还都是未定义的。为了解决这个问题,C++11引入新的语法——追踪返回类型:
template auto Sum(T1 &t1, T2 &t2) -> decltype(t1+t2) { return t1 + t2; }
这里有一个有趣的例子:
int (*(*pf())())(){ return nullptr; } auto pf1() -> auto(*)() -> int (*)(){ return nullptr; }
这里pf是函数指针的指针,而pf1,从右往左看,auto(*)()-> int (*)()是函数指针,auto pf1() -> ~,pf1显然是前面这一部分的指针,也是函数指针的指针,它们其实是等价的。
auto (*fp)() -> int与int(*fp)()是等价的。auto (&fr)() -> int与int(&fr)()也是等价的。
吐槽,有人说学了C++11再也不怕别人看懂我的代码了,所言非虚。
还记得之前的转发函数吗,之前我们只实现了没有返回值的转发函数,如果要实现有返回值的转发函数,但我们返回值的类型显然是由待转发的内容所决定的,这时候就需要追踪返回类型了:
template auto Forwarding(T && t) -> decltype(ActualFunc(forward(t))){ return ActualFunc(forward(t)); }
这样即使ActualFunc存在一些重载的返回值类型不同的版本也可以实现转发。
三、基于范围的for循环
这个不必多言,对于可确定的迭代范围(类实现了begin和end函数),并且迭代对象实现了++,--等操作符,就可以使用基于范围的for循环。
具体形式类似for(int &e : arr)这样,如果不需要改变e的值,可以去掉取引用符号。
四、unique_ptr, shared_ptr, 和weak_ptr
由废弃的auto_ptr发展而来。unique_ptr形如其名,与所指对象的内存紧密绑定,不能与其他unique_ptr类型的指针对象共享所指对象的内存。从实现上来讲,unique_ptr是一个删除了拷贝构造函数、保留了移动构造函数的指针封装类型,我们仅仅可以使用右值引用对unique_ptr进行构造,而且一旦构造成功,右值对象中的指针即被窃取。
shared_ptr同样形如其名,它允许多个该智能指针共享地拥有同一堆分配对象的内存。在实现上,shared_ptr使用了引用计数。可以通过reset方法来减少相应的引用计数。
weak_ptr稍微复杂一点,它可以指向shared_ptr指针指向的对象内存,但并不拥有该内存。而使用weak_ptr的成员lock,可以返回其所指内存的一个shared_ptr对象,若该shred_ptr无效则返回nullptr,这个特性可以用来判断shared_ptr的有效性。
上一篇: c语言:判断两个数组是否有相同的元素