博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
c++11
阅读量:2182 次
发布时间:2019-05-01

本文共 9220 字,大约阅读时间需要 30 分钟。

一, c++ 标准历程:

C++11标准是
ISO/IEC 14882:2011
- Information technology -- Programming languages -- C++ 的简称
[1]
C++11标准由 (ISO)和 (IEC)旗下的
C++标准委员会(ISO/IEC JTC1/SC22/WG21)于
2011年8月12日公布[2],并于2011年9月出版。2012年2月28日的国际标准草案(N3376)是最接近于C++11标准的草案(仅编辑上的修正)。此次标准为C++98发布后13年来第一次重大修正。

    二,    版本变更

1.对C++核心语言的扩充
2.核心语言运行期的强化(
右值引用和 move 语义;  
泛化的常数表达式;    对POD定义的修正)
3.核心语言建构期表现的加强(
外部模板)
4.核心语言使用性的加强(初始化列表;   统一的初始化;   类型推导[auto关键字] ;    以范围为基础的 for 循环;   Lambda函数与表示法;   另一种的函数语法;   对象构建的改良;    
显式
函数重载
;    空指针;     强类型枚举;     角括号;     显式类型转换;   模板的别名;    无限制的unions)
5.核心语言能力的提升(
变长参数模板;    新的
字符串字面值;     用户自定义的字面值;  
 多任务存储器模型;     thread-local的存储期限;    
使用或禁用对象的默认函数;  
 long long int 类型;    静态assertion;      允许
sizeof运算符作用在类型的数据成员上,无需明确的对象;)
6.C++标准程序库的变更(标准库组件的升级;  
线程支持
;  
多元组类型
;   散列表;
 正则表达式
;    通用
智能指针
;   可扩展的随机数功能;  
包装引用
;   多态函数对象包装器;     用于元编程的类型属性;    用于计算函数对象返回类型的统一方法)
三, 示例

类型推导与auto关键字

C++ 11 标准废除了旧的 C++ 98 标准中 auto 的意思(自动变量类型),改成了自动类型推导的意思。
在标准C/C++,使用变量必须明确的指出其类型(强类型)。然而随着模板类型的出现以及模版元编程的技巧,指定类型,特别是函数定义明确的指定返回类型,就不容易表示。在这样的情况下,将中间结果存储与变量是一件困难的事情,可能会需要知道特定的元编程程序库的内部情况。
C++11提供了两种方法缓解上述所遇到的困难。首先被有明确初始化的变量可以使用auto关键字。这会依据该初始化式的具体类型产生变量。示例:
1
auto 
otherVariable = 5;
//otherVariable被按照int型来编译
otherVariable 的类是明确定义的。因为5的类型是int,所以编译器按照“int otherVariable =5;”来编译。
1
auto 
someStrangeCallableType = boost::bind(&SomeFunction,_2,_1,someObject);
someStrangeCallableType 的类型是模版函数 boost::bind对特定引数返回的类型,作为编译器语义分析的一部分,这个类型能够简单地被编译器决定,但用户要通过查看来判断类型就不是一件容易的事情。
除此之外,C++11还定义了 decltype 能够被用来在编译器决定一个表达式的类型。举例:
1
2
int 
someInt;
decltype
(someInt) otherIntegerVariable = 5;
decltype 和 auto 一起使用会更为有用,因为 auto 变量的类型只有编译器知道。然而 decltype 对于那些大量运用运算符重载和特化的类型的代码的表示也非常有用。
auto 对于减少冗赘的代码也很有用。举例而言,程序员不用写像下面这样:
1
for
(vector<
int
>::const_iteratoritr=myvec.begin(); itr!=myvec.end(); ++itr)
可以使用auto简化为:
1
for
(
auto 
itr = myvec.begin(); itr != myvec.end(); ++itr)
这项差异随着程序员开始嵌套容器而更为显著,虽然在这种情况下 typedef 是一个减少代码的好方法。
decltype 所
表示的类型可以和 auto 推导出来的不同。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include<vector>
 
int 
main()
{
    
conststd::vector<
int
>v(1);
    
auto 
a = v[0];
//a为int类型
    
decltype
(v[0]) b = 0;
//b为constint&类型,即std::vector<int>::operator[](size_type)const的返回类型
    
auto 
c = 0;
//c为int类型
    
auto 
d = c;
//d为int类型
    
decltype
(c) e;
//e为int类型,c实体的类型
    
decltype
((c)) f = e;
//f为int&类型,因为(c)是左值
    
decltype
(0) g;
//g为int类型,因为0是右值
    
return 
0;
}

外部模板

在标准C++中,只要在编译单元内遇到被完整定义的模板,
编译器都必须将其实例化(instantiate)。这会大大增加编译时间,特别是模板在许多编译单元内使用相同的参数实例化。看起来没有办法告诉C++不要引发模板的实例化。
C++11将会引入外部模板这一概念。C++已经有了
强制编译器在特定位置开始实例化的语法
template class std::vector<MyClass>;
而C++所缺乏的是阻止编译器在某个编译单元内实例化模板的能力。C++11将简单地扩充前文语法如下:
extern template class std::vector<MyClass>;
这样就
告诉编译器不要在该编译单元内将该模板实例化
以范围为基础的for循环
Boost C++ 定义了许多"范围 (range) "的概念。范围表现有如受控制的串行 (list),持有容器中的两点。有序容器是范围概念的超集 (superset),有序容器中的两个迭代器 (iterator) 也能定义一个范围。这些概念以及操作的算法,将被并入 C++11 标准程序库。不过 C++11 将会以语言层次的支持来提供范围概念的效用。
for 语句将允许简单的范围迭代:第一部分定义被用来做范围迭代的变量,就像被声明在一般for循环的变量一样,其作用域仅只于循环的范围。而在":"之后的第二区块,代表将被迭代的范围。这样一来,就有了能够允许C-style数组被转换成范围概念的概念图。这可以是std::vector,或是其他符合范围概念的对象。
1
2
3
4
5
int 
my_array[5]={1, 2, 3, 4, 5};
for
(
int
& x : my_array)
{
x *= 2;
}
编译器支持
  
功能 VS2011 VS2013 g++ 4.7   Clang 3.1  
auto关键字 Yes Yes Yes Yes
decltype关键字 Yes Yes Yes Yes
右值引用(Rvalue references)与移动语义(move semantics) Yes Yes Yes Yes
Lambda表达式 Yes Yes Yes Yes
nullptr关键字 Yes Yes Yes Yes
静态断言(static_assert)关键字[4] Yes Yes Yes Yes
基于范围的循环(Range based for loop)语法[5] Yes Yes Yes Yes
函数返回类型后置(Trailing return type in functions)语法 Yes Yes Yes Yes
final关键字 Yes Yes Yes Yes
override关键字 Yes Yes Yes Yes
强类型枚举(Strongly typed enums) Yes Yes Yes Yes
前置枚举声明(Forward declared enums) Yes Yes Yes Yes
外部模板(extern templates) Yes Yes Yes Yes
模板右尖括号嵌套(>> for nested templates) Yes Yes Yes Yes
Local and unnamed types as template arguments Yes Yes Yes Yes
变参宏(Variadic macros) Yes Yes Yes Yes
新内建类型(New built-in types) Partial(部分) ? Yes Yes
Initializer_lists容器 No ? Yes Yes
显式类型转换运算符(explicit type conversion operators) No Yes Yes Yes
内联命名空间(Inline namespaces) No ? Yes Yes
sizeof用在没实例时的非静态成员
(sizeof on non-static data members without an instance)
No ? Yes Yes
改变union成员限制(Changed restrictions on union members) No ? Yes Yes
Raw string literals No Yes Yes Yes
User defined literals No ? Yes Yes
Encoding support in literals No ? Yes Yes
Arbitrary expressions in template deduction contexts No ? Yes Yes
默认方法(Defaulted methods) No Yes(有条件支持)[6] Yes Yes
删除方法(Deleted methods) No Yes(有条件支持)[6] Yes Yes
非静态成员初始化(Non-static data member initializers) No ? Yes Yes
变参模板(Variadic templates) No ? Yes Yes
函数模板中的默认模板参数
(Default template arguments in function templates)
No ? Yes Yes
模板别名(Template aliases) No ? Yes Yes
前置构造函数(Forwarding constructors) No ? Yes Yes
noexcept关键字 No ? Yes Yes
constexpr关键字 No ? Yes Yes
Alignment 支持 Partial(部分) Partial(部分) Yes Yes
*this的右值引用 No ? No Yes
C99兼容性(C99compatibility) Partial(部分) Partial(部分) Partial(部分) Partial(部分)
线程本地存储(Thread local storage) Partial(部分) Partial(部分) Partial(部分)  
构造函数继承(Inheriting constructors) No ? No No
Generalized attributes No ? No No
通过对比可以发现,Clang在大多数C++11功能实现上处于领先地位,而Visual Studio则稍显落后。当然,这三个编译器都有着不错的子集适用于跨平台开发。( 注:GCC4.8.1已完全支持C++11,Clang 3.3 也完全支持了C++11。最新版本的Linux 发行版(RHEL 7,CentOS 7,Ubuntu 14.06,都自带了完全支持C++11的编译器)
你可以使用类型推断、移动语义、右值引用、nullptr,static_assert,range-based参考对比。同时你还可以使用最终和重写关键字来进行友好的控制。此外,你还可以通过Enums(例举)强类型和提前声明,这里有几个改进后的模板包括extern keyword。
遗憾的是,Visual Studio并不支持较多请求的可变参数模板。另一方面,可变参数宏在这三款编译器中只支持C99标准。继承构造函数和广义属性这些特性并不是在任何地方都能获得支持。本地线程存储是是支持情况最好的一部分(通过非关键字标准)。
[7]

三, 掀起C++ 11的神秘面纱

C++标准在1998年获得通过后,有两位委员会委员预言,下一代C++标准将“肯定”包括内置的垃圾回收器(GC),但可能不会支持多线程,因为定义一个可移植的线程模型涉及到的技术太复杂了,13年后,新的C++标准C++11也接近完成,你猜怎么着?让那两位委员没想到的是,本次更新还是没有包括GC,但却包括了一个先进的线程库。C++之父Bjame Stroustrup说C++11就像一个新语言,的确,C++11核心已经发生了巨大的变化,它现在支持Lambda表达式,对象类型自动推断,统一的初始化语法,委托构造函数,deleted和defaulted函数声明nullptr,以及最重要的右值引用

C++11中值得关注的几大变化

◆ 

◆ 

◆ 

◆ 

◆ 

C++11标准库

C++于2003年以库技术报告1(TR1)的形式经历了重大改版,TR1包括新的容器类(unordered_set,unordered_map,unordered_multiset和unordered_multimap)和多个支撑正则表达式、元组和函数对象封装器等的新库。随着C++11标准获得通过,TR1和自它首次发布以来新增的库被正式纳入标准的C++标准,下面是C++11标准库的一些特性:

线程库

站在程序员的角度来看,C++11最重要的新功能毫无疑问是并行操作,C++11拥有一个代表执行线程的线程类,在并行环境中用于同步,async()函数模板启动并行任务,为线程独特的数据声明thread_local存储类型。如果你想找C++11线程库的快速教程,请阅读Anthony William的“C++0x中更简单的多线程”。

新的智能指针类

C++98只定义了一个智能指针类auto_ptr,它现在已经被废弃了,C++11引入了新的智能指针类shared_ptr和最近添加的unique_ptr,两者都兼容其它标准库组件,因此你可以在标准容器内安全保存这些智能指针,并使用标准算法操作它们。

新的算法

C++11标准库定义了新的算法模仿all_of(),any_of()和none_of()操作,下面列出适用于ispositive()到(first, first+n)范围,且使用all_of(), any_of() and none_of() 检查范围的属性的谓词:

#include 
   
//C++11 code    
//are all of the elements positive?  
all_of(first, first+n, ispositive()); //false  
//is there at least one positive element?   
any_of(first, first+n, ispositive());//true    
// are none of the elements positive?    
none_of(first, first+n, ispositive()); //false 

一种新型copy_n算法也可用了,使用copy_n()函数,复制一个包含5个元素的数组到另一个数组的代码如下:

#include   
int source[5]={0,12,34,50,80};  
int target[5];  
//copy 5 elements from source to target  
copy_n(source,5,target);  
  

算法iota()创建了一个值顺序递增的范围,好像分配一个初始值给*first,然后使用前缀++使值递增,在下面的代码中,iota()分配连续值{10,11,12,13,14}给数组arr,并将{‘a’,’b’,’c’}分配给char数组c。

include 
 
int a[5]={0};  
char c[3]={0};  
iota(a, a+5, 10); //changes a to {10,11,12,13,14}  
iota(c, c+3, 'a'); //{'a','b','c'} 

C++11仍然缺乏一些有用的库,如XML API,套接字,GUI,反射以及前面提到的一个合适的自动垃圾回收器,但C++11的确也带来了许多新特性,让C++变得更加安全,高效,易学易用。

如果C++11的变化对你来说太大的话,也不要惊慌,多花些时间逐渐消化这一切,当你完全吸收了C++11的变化后,你可能就会同意Stroustrup的说法:C++11感觉就像一个新语言,一个更好的新语言。

4, 使用C++11的一些理由

如果你的代码工作正常并且表现良好,你可能会想知道为什么还要使用C++ 11。当然了,使用用最新的技术感觉很好,但是事实上它是否值得呢? 在我看来,答案毫无疑问是肯定的。我在下面给出了9个理由,它们分为两类:性能优势和开发效率。

获得性能优势

理由1:move语义(move semantics)。简单的说,它是优化复制的一种方式。有时候复制很显然是浪费的。如果你从一个临时的string对象复制内容,简单的复制指针到字符缓冲区将比创建一个新的缓冲区再复制要高效得多。他之所以能工作是因为源对象超出了范围。

然而,在这以前C++并没有判断源对象是不是临时对象的机制。move语义通过除了复制操作外还允许你有一个move构造函数(move constructor)和一个move赋值运算(move assignment)符来提供这个机制。

你知道吗?当你在Visual Studio 2010中使用标准库中的类如string或vector时,它们已经支持move语义了。这可以防止不必要的的复制从而改善性能。

通过在你的类中实现move语义你可以获得额外的性能提升,比如当你把它们存储到STL容器中时。还有,move语义不仅可以应用到构造函数,还可以应用到方法(如vector的push_back方法)。

理由2:通过使用类别属性(type traits,如is_floating_point)和模板元编程(template metaprogramming,如enable_if template),你可以为某些特定的类型定制模版,这可以实现优化。

理由3:哈希表现在已经是标准实现的了,它提供更快速的插入、删除和查找,这在处理大量数据时很有用。你现在可以随便使用unordered_map, unordered_multimap, unordered_set 和unordered_multiset这几种数据结构了。

提高效率

提高效率不仅都是在代码性能方面,开发时间也是宝贵的。C++ 11可以让你的代码更短、更清晰、和更易于阅读,这可以让你的效率更高。

理由4:auto关键字可以自动推断类型,所以下面的代码:

vector
>::const_iterator it = v.begin() 

现在可以很简单的写成:

auto it = v.cbegin() 

尽管有些人会说,它隐藏了类型信息,在我看来它利大于弊,因为它减少了视觉混换并展示了代码的行为,还有它可以让你我少打很多字!

理由5:Lambda表达式提供了一种方法来定义匿名方法对象(实际上是闭包),这是代码更加线性和有规律可循。这在和STL算法结合使用时很方便:

bool is_fuel_level_safe(){    return all_of(_tanks.begin(), _tanks.end(),         [this](Tank& t) { return t.fuel_level() > _min_fuel_level; });}

理由6:新的智能指针(smart pointer)替换了有问题的auto_ptr,你可以不用担心内存的释放并移除相关释放内存的代码了。这让代码更清晰,并杜绝了内存泄露和查找内存泄露的时间。

理由7:把方法作为first class object是一个非常强大的特性,这让你的代码变得更灵活和通用了。C++的std::function提供了这方面的功能。方法提供一种包装和传递任何可调用的东西-函数指针, 仿函数(functor), lambda表达式等。

理由8:还有许多其它小的功能,如override、final关键字和nullptr让你的代码意图更明确。对我来说,减少视觉混乱和代码中能够更清楚地表达我的意图意味着更高兴、更高效。

另一个开发效率的方面是错误检测。如果你的错误在运行时发生,这意味着你至少需要运行软件,并可能得通过一系列步骤来重现错误,这需要时间。

C++ 11提供了一种方法来检查先决条件并尽早的在可能的时机捕获错误-编译过程中,在你运行代码前。这就是理由9

这是通过静态断言(static_assert)和类别属性模版实现的。这种方法的另一个好处是,它不需要占用任何的运行时开销,没有什么性能损失!

现在开始掌握C++ 11

在C++ 11标准中除了上描述的还有更多的改动和新功能,它需要一整本数来描述。不过,我相信它们是值得你花时间去学习的。你将省去以往花在提高效率上的时间。很多主流的编译器已经开始支持C++ 11的一些标准了。

转载地址:http://cttkb.baihongyu.com/

你可能感兴趣的文章
行为型模式之访问者模式(Visitor)
查看>>
大小端详解
查看>>
source insight使用方法简介
查看>>
<stdarg.h>头文件的使用
查看>>
C++/C 宏定义(define)中# ## 的含义 宏拼接
查看>>
Git安装配置
查看>>
linux中fork()函数详解
查看>>
C语言字符、字符串操作偏僻函数总结
查看>>
Git的Patch功能
查看>>
分析C语言的声明
查看>>
TCP为什么是三次握手,为什么不是两次或者四次 && TCP四次挥手
查看>>
C结构体、C++结构体、C++类的区别
查看>>
进程和线程的概念、区别和联系
查看>>
CMake 入门实战
查看>>
绑定CPU逻辑核心的利器——taskset
查看>>
Linux下perf性能测试火焰图只显示函数地址不显示函数名的问题
查看>>
c结构体、c++结构体和c++类的区别以及错误纠正
查看>>
Linux下查看根目录各文件内存占用情况
查看>>
A星算法详解(个人认为最详细,最通俗易懂的一个版本)
查看>>
利用栈实现DFS
查看>>