C++11新特性介绍 01
阅读目录
1. 概述
最近在看C++ Primer5 刚好看到一半,总结一下C++11里面确实加了很多新东西,如果没有任何了解,别说自己写了,看别人写的代码估计都会有些吃力。C++ Primer5是学习C++11的比较好的书籍。这篇文章仅总结关于C++11中的新东西,老的东西不再赘述。本文的所有代码仅仅值列出关键代码,并且所有特性都已经用编译器验证过,我的编译环境 gcc 5.3.1 g++ 5.3.1 ,据说 4.7以上的版本已经支持大部分C++11的特性,VS系列的编译器对C++11的支持情况不甚了解,如果没有合适的编译器,可以点击这里 C++shell 这是一个在线的C++编译系统,里面有多个选项可以选择C++98,C++11,C++14等,可以在这里面验证C++11的正确性。
2. long long 类型
long long 类型实际上没有在C++ 98中存在,而之后被C99标准收录,其实现在市面上大多数编译器是支持 long long 的,但是这个类型正式成为C++的标准类型是在C++11中。标准要求long long至少是64位也就是8个字节。一个字面常量使用LL后缀表示long long类型,使用ULL后缀表示unsigned long long 类型。
3. 列表初始化
C++11中全面加入了列表初始化的功能,包括对vector,map,值类型,struct等等都可以使用列表初始化,还可以在函数中返回一个花括号括起来的列表,而在这之前我们只能对数组进行列表初始化:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
//数组列表初始化int xx[5]={1,2,3,4,5};int yy[]={6,7,8,9,0};//值类型进行初始化int a{10};int b={10};int c={10.123}; // 编译器报错,g++ 5.3.1当列表初始化用于值类型的时候,如果有精度损失,编译器会报错。//列表初始化还可以用结构体typedef struct Str{ int x; int y;}Str;Str s = {10,20};//列表初始化类,必须是public成员,如果含有私有成员会失败class Cls{public: int x; int y;};Cls c = {10,20};//vector不仅可以使用列表初始化,还可以使用列表进行赋值,数组不能用列表赋值vector<int>v1={1,2,3,4,5,6,7,8,9}; // 初始化vector<int>v2;v2={3,4,5,6,7}; //赋值//map列表初始化map<string ,int> m = { {"x",1}, {"y",2}, {"z",3}};//用函数返回初始化列表只展示关键代码,相关头文件自行添加//同理结构体,类,map的返回也可以使用初始化列表返回vector<int> getVector(){ return {1,2,3,4,5};}int main(){ vector<int> v = getVector(); cout<<v[0]<<v[1]<<v.size()<<endl; return 0 ;} |
4. nullptr 空指针
C++11中新加入的字面值表示不指向任何对象的空指针,以前我们常常用一个预定义的宏NULL来表示空指针,实际上NULL的值是0,新标准推荐使用nullptr而不是NULL
5. constexpr变量
我们在定义常量的时候一般使用const来定义,一个常量必须在定义的时候进行初始化,并且之后不可更改。一个常量必须使用一个常量表达式进行初始化,并且在编译期间就可以得到常量的值,但是如何确定一个表达式就是常量表达式呢,这个通常是由程序员自己确定的,例如:
|
1
2
3
4
5
6
|
const int a =20;//20是一个字面值,当然也是一个常量表达式,所以用20来为a赋值是没有问题的//然而下面的代码也可以通过编译,g++ 5.3.1int a = 20 ;const int x = a;int b[x]={0}; |
为常量x赋值的是一个变量a,这样做应该是不合理的,但是编译器没有报告任何错误,当然这种错误是显而易见的,但是在复杂的系统中如何判断一个表达式是否是常量表达式是很困难的,例如这里的a我们一眼就可以判断其并不是一个常量表达式。为此C++11提供了一个新的关键字constexpr,使用该关键字定义的常量,由编译器检查为其赋值的表达式是否是常量表达式,例如上面的代码改成:
|
1
2
|
int a = 20 ;constexpr int x = a; |
编译器编译的时候就会报错说a并不是常量。显然constexpr关键字将常量表达式的检查转交给编译器处理,而不是程序员自己,所以使用constexpr定义常量要比const安全。
6. constexpr函数
普通的函数一般是不能用来为constexpr常量赋值的,但是C++11允许定义一种constexpr的函数,这种函数在编译期间就可以计算出结果,这样的函数是可以用来为constexpr赋值的。定义constexpr函数需要遵守一些约定,函数的返回类型以及所有形参的类型都应该是字面值,一般情况下函数体中必须有且只有一条return语句。
|
1
2
3
4
5
6
|
constexpr int size(){ return 42;}constexpr int si = size(); |
执行初始化的时候编译器将函数的调用替换成结果值,constexpr函数体中也可以出现除了return之外的其他语句,但是这些语句在运行时不应该执行任何操作,例如空语句,using声明等。constexpr函数允许其返回值并非是一个字面值,例如:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
constexpr int size(int s){ return s*4;}int a = 20;const int b = 30;constexpr int c = 40;constexpr int si = size(a); //error a是一个变量所以函数返回的是一个可变的值constexpr int si1 = size(20); //ok 函数返回的实际上是一个常量constexpr int si2 = size(b); //okconstexpr int si3 = size(c); //ok |
由上可知constexpr函数并不一定返回常量,如果应用于函数的参数是一个常量表达式则返回常量,否则返回变量,而该函数调用到底是一个常量表达式还是非常量表达式则由编译器来判断。这就是constexpr的好处。
7. using类型别名
类型别名其实早在C语言中就有了,一般情况下我们使用关键字typedef来声明一个类型的别名,在C++11中增加了另一种声明类型别名的方法就是使用using关键字,using关键字在C++11以前一般用来引用命名空间。
|
1
2
3
4
5
|
typedef int INT; // 右侧符号代表左侧using INT2 = int; // 左侧符号代表右侧INT a = 20;INT2 b = 30; |
8. auto类型指示符
我们定义一个变量的时候首先必须确定该变量的类型,而很多时候并不是我们先需要一个变量然后为该变量赋值合适的数据,而是我们有一个值但是我们却不知道该用什么类型的变量存储它,特别是C++的模版使用的非常广泛,有时候要定义一个变量,其类型是很复杂的会带有模版的类型参数,例如一个最常见的例子:
|
1
2
|
map<string ,int> m ;map<string,int>::iterator it = m.begin(); |
上面的例子中我们定义了一个map<string,int>::iterator类型的变量来存放 m.begin()的值,这个例子相对来说还不算困难但是我在开始使用map容器的时候也曾经被搞晕过,如果map是一个 map<string,double> 类型则需要定义一个 map<string.double>::iterator it 来存放了。特别是如果map和vector之间互相嵌套的情况就更容易弄错了。定义这种类型变量的另一个缺点就是一个类型的名字往往会很长,试想一下程序代码中通篇都是这种变量声明,恐怕不会有几个人看着舒服吧。不过没关系C++11为我们定义了一个新的关键字 auto 用来定义变量,而变量的类型由编译器自动根据赋值的表达式推导出来,不需要我们显示定义了。因为auto定义的变量的类型由编译器根据赋值的表达式推导,所以auto定义的变量必须有初始值,否则编译器没法确定该变量的类型。
|
1
2
3
4
|
auto x = 20; // x 是intauto y = 3.14; // y 是doublemap<string ,int> m ;auto it = m.begin(); //it 是map<string,int>::iterator |
这样是不是方便了不少,而且程序看起来更加简洁了
auto可以在一条语句中声明多个变量,但是要保证语句中的基础数据类型只有一个,例如:
|
1
2
|
auto i=10,*p=&i; // OK i是int,p是int*auto a=10,b=3.14; // Error 类型是int还是double ? |
9. decltype类型指示符
有时候会有这样的需求,我们需要知道一个表达式的类型,并使用该类型去定义一个变量,例如:
|
1
2
3
|
int a = 10;int b = 20;auto c = a + b; // OK a+b的类型是int,此时c的类型是int,并且c的值是 a+b |
auto可以解决部分问题,例如我们定义的变量的类型就是表达式 a+b 的类型,但是如果我们仅仅需要定义一个与表达式 a+b 的类型相同的变量,但是我们又不希望将表达式a+b的值赋值给刚刚定义的变量,我们希望赋另外一个值或者是仅仅定义变量而不赋值呢。 这就需要用到C++11 提供的另一个类型说明符 decltype了。decltype作用于一个表达式,并且返回该表达式的类型,在此过程中编译器分析表达式的类型,并不会计算表达式的值。例如
|
1
2
3
|
int a = 10;int b = 20;decltype(a+b) c = 50; // OK c的类型就是 a+b 的类型int |
对于引用类型decltype有一些特别的地方:
|
1
2
3
4
|
int a = 20 ;int &b = a;decltype(b) c ; // Error c是引用类型必须赋值decltype(b) d = a; // OK d是引用类型,指向a |
可以看到decltype如果作用于一个引用类型,其得到的还是一个引用类型。我们知道一个引用类型在使用的时候一般会当作其关联的那个变量的同义词处理,例如如果使用 cout<<b<<endl; 其中b实际上相当于a,但是decltype作用于引用类型的时候会保留引用性质。
如果一个表达式是一个解指针引用的操作,decltype得到的也是一个引用类型:
|
1
2
3
4
5
|
int a = 20 ;int *p = &a;decltype(*p) c = a; // c的类型是int&c = 50;cout<<a<<endl; // 输出50 |
当decltype作用于一个变量的时候,变量加不加括号是有区别的,例如:
|
1
2
3
|
int a = 20;decltype(a) b = 30; //ok b的类型是 intdecltype((a)) c = a ; // ok c的类型是int& 其关联变量 a |
加上括号之后编译器会把(a)当作是一个表达式处理,而变量是一种可以作为赋值语句左值的表达式,所以会解释成引用类型。
C++11新特性介绍 01的更多相关文章
- Java 11 新特性介绍
Java 11 已于 2018 年 9 月 25 日正式发布,之前在Java 10 新特性介绍中介绍过,为了加快的版本迭代.跟进社区反馈,Java 的版本发布周期调整为每六个月一次——即每半年发布一个 ...
- C++11新特性介绍 02
阅读目录 1. 范围for语句 2. 尾置返回类型 3. =default 生成默认构造函数 4. 类对象成员的类内初始化 5. lambda表达式与bind函数 6. 智能指针share_ptr,u ...
- [转载] C++11新特性
C++11标准发布已有一段时间了, 维基百科上有对C++11新标准的变化和C++11新特性介绍的文章. 我是一名C++程序员,非常想了解一下C++11. 英文版的维基百科看起来非常费劲,而中文版维基百 ...
- C++11 新特性之智能指针(shared_ptr, unique_ptr, weak_ptr)
这是C++11新特性介绍的第五部分,涉及到智能指针的相关内容(shared_ptr, unique_ptr, weak_ptr). shared_ptr shared_ptr 基本用法 shared_ ...
- Java 12 新特性介绍,快来补一补
Java 12 早在 2019 年 3 月 19 日发布,它不是一个长久支持(LTS)版本.在这之前我们已经介绍过其他版本的新特性,如果需要可以点击下面的链接进行阅读. Java 11 新特性介绍 J ...
- C++11新特性总结 (二)
1. 范围for语句 C++11 引入了一种更为简单的for语句,这种for语句可以很方便的遍历容器或其他序列的所有元素 vector<int> vec = {1,2,3,4,5,6}; ...
- Hadoop3.0新特性介绍,比Spark快10倍的Hadoop3.0新特性
Hadoop3.0新特性介绍,比Spark快10倍的Hadoop3.0新特性 Apache hadoop 项目组最新消息,hadoop3.x以后将会调整方案架构,将Mapreduce 基于内存+io+ ...
- jdk7和8的一些新特性介绍
jdk7和8的一些新特性介绍 本文是我学习了解了jdk7和jdk8的一些新特性的一些资料,有兴趣的大家可以浏览下下面的内容. 官方文档:http://www.oracle.com/technetwor ...
- webpack 4.0.0-beta.0 新特性介绍
webpack 可以看做是模块打包机.它做的事情是:分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式 ...
随机推荐
- css 基础-1
css 基础-1 一. HTML框架 (frameset) 属性: noresize(不可移动), border(边框线的大小), rows(分割成行), cols(分割列) ...
- BZOJ 3529 【SDOI2014】 数表
题目链接:数表 我们一起来膜PoPoQQQ大爷的题解吧Orz 首先我们来考虑没有\(a\)的限制该怎么做.显然交换\(n\),\(m\)答案不变,所以后面默认\(n \le m\). 我们定义两个函数 ...
- 【测试设计】基于正交法的测试用例设计工具--PICT
前言 我们都知道成对组合覆盖是一种非常有效的测试用例设计方法,但是实际工作过程中当成对组合量太大,我们往往很难做到有效的用例覆盖. PICT是微软公司出品的一款成对组合命令行生成工具,它很好的解决了上 ...
- 【Docker】Segmentation Fault or Critical Error encountered. Dumping core and abort
背景 CentOS7 安装Docker后,load镜像时出现以下错误: Segmentation Fault or Critical Error encountered. Dumping core a ...
- django使用bootstrap快速美化 admin后台
使用django-admin-bootstrappe快速美化后台 两步: 1.pip install django-admin-bootstrapped 安装应用 2.在setting.py里面添加 ...
- 将input type="file" 类型的图片文件转成base64
带有图片的form表单上传数据是很麻烦的,因为图片通常都是和文字分开上传,这是很麻烦的,所有吧图片转成base64就可以和当成文字上传了.话不多少,看代码: 首先定义一个类型为file的input标签 ...
- HDU-5700-贪心/stl
区间交 Time Limit: 8000/4000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)Total Submiss ...
- DOM之概述
body, table{font-family: 微软雅黑; font-size: 10pt} table{border-collapse: collapse; border: solid gray; ...
- C#中IEnumerable和IEnumerator区别
IEnumerator:是一个真正的集合访问器,提供在普通集合中遍历的接口,有Current,MoveNext(),Reset(),其中Current返回的是object类型.IEnumerable: ...
- windows 下键盘映射
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Keyboard Layout下添加二进制键 Scancode Map完后注销后即可生效