欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

C++11的新特性介绍

程序员文章站 2022-05-25 12:23:30
一、auto无法带走cv限制符 在C++标准中,const和volatile被称为“cv限制符,cv-qualifier”,它们分别代表了变量的两种不同的...

一、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的有效性。