c++11 标准.docx
- 文档编号:26844238
- 上传时间:2023-06-23
- 格式:DOCX
- 页数:51
- 大小:49.10KB
c++11 标准.docx
《c++11 标准.docx》由会员分享,可在线阅读,更多相关《c++11 标准.docx(51页珍藏版)》请在冰豆网上搜索。
c++11标准
C++11[编辑]
(重定向自C++0x)
C++11,先前被称作C++0x,即ISO/IEC14882:
2011,是C++编程语言的一个标准。
它取代第二版标准ISO/IEC14882:
2003(第一版ISO/IEC14882:
1998公开于1998年,第二版于2003年更新,分别通称C++98以及C++03,两者差异很小),且已被C++14取代。
相比于C++03,C++11标准包含核心语言的新机能,而且扩展C++标准程序库,并入了大部分的C++TechnicalReport1程序库(数学的特殊函数除外)。
ISO/IECJTC1/SC22/WG21C++标准委员会计划在2010年8月之前完成对最终委员会草案的投票,以及于2011年3月召开的标准会议完成国际标准的最终草案。
然而,WG21预期ISO将要花费六个月到一年的时间才能正式发布新的C++标准。
为了能够如期完成,委员会决定致力于直至2006年为止的提案,忽略新的提案[1]。
最终于2011年8月12日公布,并于2011年9月出版。
2012年2月28日的国际标准草案[1]是最接近于C++11标准的草案,差异仅有编辑上的修正。
像C++这样的编程语言,通过一种演化的的过程来发展其定义。
这个过程不可避免地将引发与现有代码的兼容问题,在C++的发展过程中偶尔会发生。
不过根据比雅尼·斯特劳斯特鲁普(C++的创始人并且是委员会的一员)表示,新的标准将几乎100%兼容于现有标准。
目录[隐藏]
1候选变更
2C++核心语言的扩充
3核心语言的运行期表现强化
3.1右值引用和move语义
3.2泛化的常数表示式
3.3对POD定义的修正
4核心语言构造期表现的加强
4.1外部模板
5核心语言使用性的加强
5.1初始化列表
5.2统一的初始化
5.3类型推导
5.4以范围为基础的for循环
5.5Lambda函数与表示式
5.6回返类型后置的函数声明
5.7对象构造的改良
5.8显式虚函数重载
5.9空指针
5.10强类型枚举
5.11角括号
5.12显式类型转换子
5.13模板的别名
5.14无限制的unions
6核心语言能力的提升
6.1变长参数模板
6.2新的字符串字面值
6.3用户自定义的字面值
6.4多任务内存模型
6.5thread-local的存储期限
6.6使用或禁用对象的默认函数
6.7longlongint类型
6.8静态assertion
6.9允许sizeof运算符作用在类的数据成员上,无须明确的对象
6.10垃圾回收机制
7C++标准程序库的变更
7.1标准库组件上的升级
7.2线程支持
7.3多元组类型
7.4散列表
7.5正则表达式
7.6通用智能指针
7.7可扩展的随机数功能
7.8包装引用
7.9多态函数对象包装器
7.10用于元编程的类型属性
7.11用于计算函数对象回返类型的统一方法
8已被移除或是不包含在C++11标准的特色
9被移除或废弃的特色
10编译器实现
11关系项目
12参考资料
12.1C++标准委员会文件
12.2文章
13外部链接
§候选变更[编辑]
C++的修订包含核心语言以及标准程序库。
在发展新标准的每个机能上,委员会采取了几个方向:
维持与C++98,可能的话还有C之间的稳定性与兼容性;
尽可能不通过核心语言的扩展,而是通过标准程序库来引进新的特色;
能够演进编程技术的变更优先;
改进C++以帮助系统以及库设计,而不是引进只针对特别应用的新特色;
增进类型安全,提供对现行不安全的技术更安全的替代方案;
增进直接对硬件工作的能力与表现;
提供现实世界中问题的适当解决方案;
实行“zero-overhead”原则(某些功能要求的额外支持只有在该功能被使用时才能使用);
使C++易于教授与学习
对初学者的注重被认为是重要的,因为他们构成了计算机程序员的主体。
也因为许多初学者不愿扩展他们对C++的知识,只限于使用他们对C++专精的部分。
此外,考虑到C++被广泛的使用(包含应用领域和编程风格),即便是最有经验的程序员在面对新的编程范式时也会成为初学者。
§C++核心语言的扩充[编辑]
C++委员会的主要焦点是在语言核心的发展上。
核心语言将被大幅改善的领域包括多线程(或称为“多线程”)支持、泛型编程、统一的初始化,以及性能表现的加强。
在此分成4个区块来讨论核心语言的特色以及变更:
运行期表现强化、构造期表现强化、可用性强化,还有新的功能。
某些特色可能会同时属于多个区块,但在此仅于其最具代表性的区块描述该特色。
§核心语言的运行期表现强化[编辑]
以下的语言机能主要用来提升某些性能表现,像是内存或是速度上的表现。
§右值引用和move语义[编辑]
在C++03及之前的标准,临时对象(称为右值"R-values",位于赋值运算符之右)无法被改变,在C中亦同(且被视为无法和constT&做出区分)。
尽管在某些情况下临时对象的确会被改变,甚至也被视为是一个有用的漏洞。
C++11增加一个新的非常数引用(reference)类型,称作右值引用(R-valuereference),标记为T&&。
右值引用所引用的临时对象可以在该临时对象被初始化之后做修改,这是为了允许move语义。
C++03性能上被长期被诟病的其中之一,就是其耗时且不必要的深度拷贝。
深度拷贝会发生在当对象是以传值的方式传递。
举例而言,std:
:
vector
:
vector
:
vector
该临时对象和其拥有的内存会被摧毁。
(为了讨论上的方便,这里忽略回返值优化)
在C++11,一个std:
:
vector的"move构造函数"对某个vector的右值引用可以单纯地从右值复制其内部C-style数组的指针到新的vector,然后留下空的右值。
这个操作不需要数组的复制,而且空的临时对象的析构也不会摧毁内存。
传回vector临时对象的函数不需要显式地传回std:
:
vector
如果vector没有move构造函数,那么复制构造函数将被调用,以conststd:
:
vector
如果它确实有move构造函数,那么就会调用move构造函数,这能够免除大幅的内存配置。
基于安全的理由,具名的参数将永远不被认定为右值,即使它是被如此声明的;为了获得右值必须使用std:
:
move
boolis_r_value(int&&){returntrue;}
boolis_r_value(constint&){returnfalse;}
voidtest(int&&i)
{
is_r_value(i);//i為具名變數,即使被宣告成右值也不會被認定是右值。
is_r_value(std:
:
move
:
move
}
由于右值引用的用语特性以及对于左值引用(L-valuereferences;regularreferences)的某些用语修正,右值引用允许开发者提供完美转发(perfectfunctionforwarding)。
当与变长参数模板结合,这项能力允许函数模板能够完美地转送引用给其他接受这些特定引用的函数。
最大的用处在于转送构造函数参数,创造出能够自动为这些特定引用调用正确构造函数的工厂函数(factoryfunction)。
§泛化的常数表示式[编辑]
C++本来就已具备常数表示式(constantexpression)的概念。
像是3+4总是会产生相同的结果并且没有任何的副作用。
常数表示式对编译器来说是优化的机会,编译器时常在编译期运行它们并且将值存入程序中。
同样地,在许多场合下,C++标准要求使用常数表示式。
例如在数组大小的定义上,以及枚举值(enumeratorvalues)都要求必须是常数表示式。
然而,常数表示式总是在遇上了函数调用或是对象构造函数时就终结。
所以像是以下的例子是不合法的:
intGetFive(){return5;}
intsome_value[GetFive()+5];//欲產生10個整數的陣列。
不合法的C++寫法
这不是合法的C++,因为GetFive()+5并不是常数表示式。
编译器无从得知GetFive实际上在运行期是常数。
理论上而言,这个函数可能会影响全域参数,或者调用其他的非运行期)non-runtime)常数函数等。
C++11引进关键字constexpr允许用户保证函数或是对象构造函数是编译期常数。
以上的例子可以被写成像是下面这样:
constexprintGetFive(){return5;}
intsome_value[GetFive()+5];//欲產生10個整數的陣列。
合法的C++11寫法
这使得编译器能够了解并去验证GetFive是个编译期常数。
对函数使用constexpr在函数可以做的事上面加上了非常严格的条件。
首先,该函数的回返值类型不能为void。
第二点,函数的内容必须依照"returnexpr"的形式。
第三点,在引用取代后,expr必须是个常数表示式。
这些常数表示式只能够调用其他被定义为constexpr的函数,或是其他常数表示式的数据参数。
最后一点,有着这样标签的函数直到在该编译单元内被定义之前是不能够被调用的。
声明为constexpr的函数也可以像其他函数一样用于常量表达式以外的地方,此时不需要满足后两点。
参数也可以被定义为常数表示式值:
constexprdoubleforceOfGravity=9.8;
constexprdoublemoonGravity=forceOfGravity/6.0;
常数表示式的数据参数是隐式的常数。
他们可以只存储常数表示式或常数表示式构造函数的结果。
为了从用户自定类型(user-definedtype)构造常数表示式的数据参数,构造函数也可以被声明成constexpr。
与常数表示式函数一样,常数表示式的构造函数必须在该编译单元内使用之前被定义。
他必须有着空的函数本体。
它必须用常数表示式初始化他的成员(member)。
而这种类型的析构函数应当是无意义的(trivial),什么事都不做。
复制constexpr构造起来的类型也应该被定义为constexpr,这样可以让他们从常数表示式的函数以值传回。
类的任何成员函数,像是复制构造函数、重载的运算符等等,只要他们符合常数表示式函数的定义,都可以被声明成constexpr。
这使得编译器能够在编译期进行类的复制、对他们施行运算等等。
常数表示式函数或构造函数,可以以非常数表示式(non-constexpr)参数调用。
就如同constexpr整数字面值能够指派给non-constexpr参数,constexpr函数也可以接受non-constexpr参数,其结果存储于non-constexpr参数。
constexpr关键字只有当表示式的成员都是constexpr,才允许编译期常数性的可能。
§对POD定义的修正[编辑]
在标准C++,一个结构(struct)为了能够被当成POD,必须遵守几条规则。
有很好的理由使我们想让大量的类型符合这种定义,符合这种定义的类型能够允许产生与C兼容的对象布局(objectlayout)。
然而,C++03的规则太严苛了。
C++11将会放宽关于POD的定义。
当class/struct是极简的(trivial)、属于标准布局(standard-layout),以及他的所有非静态(non-static)成员都是POD时,会被视为POD。
一个极简的类或结构符合以下定义:
极简的默认构造函数。
这可以使用默认构造函数语法,例如SomeConstructor()=default;
极简的复制构造函数,可使用默认语法(defaultsyntax)
极简的赋值运算符,可使用默认语法(defaultsyntax)
极简的析构函数,不可以是虚拟的(virtual)
一个标准布局(standard-layout)的类或结构符合以下定义:
只有非静态的(non-static)数据成员,且这些成员也是符合标准布局的类型
对所有non-static成员有相同的访问控制(public,private,protected)
没有虚函数
没有虚拟基类
只有符合标准布局的基类
没有和第一个定义的non-static成员相同类型的基类
若非没有带有non-static成员的基类,就是最底层(继承最末位)的类没有non-static数据成员而且至多一个带有non-static成员的基类。
基本上,在该类的继承体系中只会有一个类带有non-static成员。
§核心语言构造期表现的加强[编辑]
§外部模板[编辑]
在标准C++中,只要在编译单元内遇到被完整定义的模板,编译器都必须将其实例化(instantiate)。
这会大大增加编译时间,特别是模板在许多编译单元内使用相同的参数实例化。
看起来没有办法告诉C++不要引发模板的实例化。
C++11将会引入外部模板这一概念。
C++已经有了强制编译器在特定位置开始实例化的语法:
templateclassstd:
:
vector
而C++所缺乏的是阻止编译器在某个编译单元内实例化模板的能力。
C++11将简单地扩充前文语法如下:
externtemplateclassstd:
:
vector
这样就告诉编译器不要在该编译单元内将该模板实例化。
§核心语言使用性的加强[编辑]
这些特色存在的主要目的是为了使C++能够更容易使用。
举凡可以增进类型安全,减少代码重复,不易误用代码之类的。
§初始化列表[编辑]
标准C++从C带来了初始化列表(initializerlist)的概念。
这个构想是结构或是数组能够依据成员在该结构内定义的顺序通过给予的一串引用来产生。
这些初始化列表是递归的,所以结构的数组或是包含其他结构的结构可以使用它们。
这对静态列表或是仅是把结构初始化为某值而言相当有用。
C++有构造函数,能够重复对象的初始化。
但单单只有那样并不足以取代这项特色的所有机能。
在C++03中,只允许在严格遵守POD的定义和限制条件的结构及类上使用这项机能,非POD的类型不能使用,就连相当有用的STL容器std:
:
vector也不行。
C++11将会把初始化列表的概念绑到类型上,称作std:
:
initializer_list。
这允许构造函数或其他函数像参数般地使用初始化列表。
举例来说:
classSequenceClass
{
public:
SequenceClass(std:
:
initializer_list
};
这将允许SequenceClass由一连串的整数构造,就像:
SequenceClasssomeVar={1,4,5,6};
这个构造函数是种特殊的构造函数,称作初始化列表构造函数。
有着这种构造函数的类在统一初始化的时候会被特别对待。
类std:
:
initializer_list<>是个第一级的C++11标准程序库类型。
然而他们只能够经由C++11编译器通过{}语法的使用被静态地构造。
这个列表一经构造便可复制,虽然这只是copy-by-reference。
初始化列表是常数;一旦被创建,其成员均不能被改变,成员中的数据也不能够被变动。
因为初始化列表是真实类型,除了类构造函数之外还能够被用在其他地方。
正规的函数能够使用初始化列表作为引用。
例如:
voidFunctionName(std:
:
initializer_list
FunctionName({1.0f,-3.45f,-0.4f});
标准容器也能够以这种方式初始化:
vector
§统一的初始化[编辑]
标准C++在初始化类型方面有着许多问题。
初始化类型有数种方法,而且交换使用时不会都产生相同结果。
传统的构造函数语法,看起来像是函数声明,而且为了能使编译器不会弄错必须采取一些步骤。
只有集合体和POD类型能够被集合式的初始化(使用SomeTypevar={/*stuff*/};)。
C++11将会提供一种统一的语法初始化任意的对象,它扩充了初始化列表语法:
structBasicStruct
{
intx;
floaty;
};
structAltStruct
{
AltStruct(int_x,float_y):
x(_x),y(_y){}
private:
intx;
floaty;
};
BasicStructvar1{5,3.2f};
AltStructvar2{2,4.3f};
var1的初始化的运作就如同C-style的初始化列表。
每个公开的参数将被对应于初始化列表的值给初始化。
隐式类型转换会在需要的时候被使用,这里的隐式类型转换不会产生范围缩限(narrowing)。
要是不能够转换,编译便会失败。
(范围缩限(narrowing):
转换后的类型无法表示原类型。
如将32-bit的整数转换为16-bit或8-bit整数,或是浮点数转换为整数。
)var2的初始化则是简单地调用构造函数。
统一的初始化构造能够免除具体指定特定类型的必要:
structIdString
{
std:
:
stringname;
intidentifier;
};
IdStringvar3{"SomeName",4};
该语法将会使用constchar*参数初始化std:
:
string。
你也可以做像下面的事:
IdStringGetString()
{
return{"SomeName",4};//注意這裡不需要明確的型別
}
统一初始化不会取代构造函数语法。
仍然会有需要用到构造函数语法的时候。
如果一个类拥有初始化列表构造函数(TypeName(initializer_list
C++11版本的std:
:
vector将会有初始化列表构造函数。
这表示:
std:
:
vector
这将会调用初始化列表构造函数,而不是调用std:
:
vector只接受一个尺寸参数产生相应尺寸vector的构造函数。
要使用这个构造函数,用户必须直接使用标准的构造函数语法。
§类型推导[编辑]
在标准C++和C,使用参数必须明确的指出其类型。
然而,随着模版类型的出现以及模板元编程的技巧,某物的类型,特别是函数定义明确的回返类型,就不容易表示。
在这样的情况下,将中间结果存储于参数是件困难的事,可能会需要知道特定的元编程程序库的内部情况。
C++11提供两种方法缓解上述所遇到的困难。
首先,有被明确初始化的参数可以使用auto关键字。
这会依据该初始化子(initializer)的具体类型产生参数:
autosomeStrangeCallableType=boost:
:
bind(&SomeFunction,_2,_1,someObject);
autootherVariable=5;
someStrangeCallableType的类型就是模板函数boost:
:
bind对特定引用所回返的类型。
作为编译器语义分析责任的一部份,这个类型能够简单地被编译器决定,但用户要通过查看来判断类型就不是那么容易的一件事了。
otherVariable的类型同样也是定义明确的,但用户很容易就能判别。
它是个int(整数),就和整数字面值的类型一样。
除此之外,decltype能够被用来在编译期决定一个表示式的类型。
举例:
intsomeInt;
decltype(someInt)otherIntegerVariable=5;
decltype和auto一起使用会更为有用,因为auto参数的类型只有编译器知道。
然而decltype对于那些大量运用运算符重载和特化的类型的代码的表示也非常有用。
auto对于减少冗赘的代码也很有用。
举例而言,程序员不用写像下面这样:
for(vector
:
const_iteratoritr=myvec.cbegin();itr!
=myvec.cend();++itr)
而可以用更简短的
for(autoitr=myvec.cbegin();itr!
=myvec.cend();++itr)
这项差异随着程序员开始嵌套容器而更为显著,虽然在这种情况下typedef是一个减少代码的好方法。
decltype所表示的类型可以和auto推导出来的不同。
#include
intmain()
{
conststd:
:
vector
(1);
autoa=v[0];//a為int型別
decltype(v[0])b=0;//b為constint&型別,即
//std:
:
vector
:
operator[](size_type)const的回返型別
autoc=0;//c為int型別
autod=c;//d為int型別
decltype(c)e;//e為int型別,c實體的型別
decltype((c))f=e;//f為int&型別,因為(c)是左值
decltype(0)g;//g為int型別,因為0是右值
}
§以范围为基础的for循环[编辑]
BoostC++定义了许多"范围(range)"的概念。
范围表现有如受控制的列表(list),持有容器中的两点。
有序容器是范围概念的超集(superset),有序容器中的两个迭代器(iterator)也能定义一个范围。
这些概念以及操作的算法,将被并入C++11标准程序库。
不过C++11将会以语言层次的支持来提供范围概念的效用。
for述句将允许简单的范围迭代:
intmy_array[5]={1,2,3,4,5};
for(int&x:
my_array)
{
x*=2;
}
上面for述句的第一部份定义被用来做范围迭代的参数,就像被声明在一般for循环的参数一样,其作用域仅只于循环的范围。
而在":
"之后的第二区块,代表将被迭代的范围。
这样一来,就有了能够允许C-style数组被转换成范围概念的概念图。
这可以是std:
:
vector,或是其他符合范围概念的对象。
§Lambda函数与表示式[编辑]
在标准C++,特别是当使用C++标准程序库算法函数诸如sort和find,用户经常希望能够在算法函数调用的附近定义一个临时的述部函数(又称谓词函数,predicatefunction)。
由于语言本身允许在函数内部定义类,可以考虑使用函数对象,然而这通常既麻烦又冗赘,也阻碍了代码的流程。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- c+11 标准 c+ 11