C++Primer第五版对C++11的特性做了详细的介绍,现在对其做一个大致的归纳.
一、long long类型
在C++11中,标准要求long long整型可以在不同平台上有不同的长度,但至少有64位。我们在写常数字面量时,可以使用LL后缀(或是ll)标识一个long long类型的字面量,而ULL(或ull、Ull、uLL)表示一个unsigned long long类型的字面量。比如:
long long int lli = -9000000000000000000LL;
unsigned long long int ulli = -9000000000000000000ULL;
二、列表初始化
初始化不是赋值,初始化的含义是创建变量时赋予其一个初始值,而赋值的含义是把对象的当前值擦除,而以一个新值来替代。
c++语言定义了初始化的好几种不同形式,这也是初始化问题复杂性的一个提现。例如,想要定义一个名为units_sold的int变量并初始化为0,以下的4条语句都可以做到这点:
int units_sold = 0;
int units_sold = {0};
int units_sold{0};
int units_sold(0);
在C++98中,我们可以使用以下两种方法进行初始化:
int i = 0;
int j(0);
引入“初始化列表”后,我们可以这样进行初始化:
int i = {0};
int j{0};
上述代码体现不出“初始化列表”的优越来,别着急,我们还可以这样用:
std::vector<int> v{ 1, 2, 3, 4 };
std::map<int, float> m = { {1, 1.0f}, {2, 2.0f}, {3, 3.0f} };
三、nullptr常量
空指针(null pointer)不指向任何对象,在试图使用一个指针之前代码可以首先检查它是否为空,列出几个生成空指针的方法:
int *p = nullptr; //等价于int *p = 0;
int *p = 0; //直接将p2初始化为字面常量0
//需要首先 #include cstdlib
int *p3 = NULL //等价于int *p3 = 0;
得到空指针最直接的办法就是用字面值nullptr来初始化指针,这也是C++11新标准引入的一种方法。nullptr是一种特殊类型的字面值,它可以转换为任意其他的指针类型。
另一种方法就如对p2的定义一样,它可以通过将指针初始化为字面值0来生成空指针。
过去的程序还会用到一个名为NULL的预处理变量来给指针赋值,这个变量在头文件cstdlib中定义,它的值就是0,当用到一个预处理变量时,预处理器会自动地将它替换为实际值,因此用NULL初始化指针和用0初始化指针是一样的。在新标准下,现在的C++程序最好使用nullptr,同时尽量避免使用NULL。
四、constexpr变量
c++11新标准规定,允许将变量声明为constexpr类型以便由编译器来验证变量的值是否是一个常量表达式。
声明为constexpr的变量一定是一个常量,而且必须用常量表达式初始化:
constexpr int mf = 20; //20是常量表达式
constexpr int limit = mf + 1; //mf+1是常量表达式
constexpr int sz = size(); //只有当size是一个constexpr函数时,才是一条正确的声明语句
五、类型别名声明
传统的方法是使用typedef关键字来定义类型别名
在新标准中规定了一种新的方法,使用别名声明来定义类型的别名:
using SI = Sales_item; //SI是Sales_item的同义词
这种方法用关键字using作为别名声明的开始,其后紧跟别名和等号,其作用是把等号左侧的名字规定成等号右侧类型的别名
六、auto类型指示符
编程时常常需要把表达式的值赋给变量,这就要求在声明变量的时候清楚地知道表达式的类型。然而做到这点并非那么容易。
为了解决这个问题,c++11新标准引入了auto类型说明符,用它就能让编译器替我们去分析表达式的类型。
//由val1和val2相加的结果可以推断出item的类型
auto item = val1 + val2; //item初始化为val1和val2相加的结果
使用auto也可以在一条语句中声明多个变量,因为一条语句只能有一个基本数据类型,所以该语句中所有变量的初始基本数据类型必须一样:
aotu i = 0, *p = &i; //正确,i是整数、p是整数指针
auto sz = 0, pi = 3.14; //错误:sz和pi的类型不一致
const int ci = 0;
auto &g = ci; //g是一个整形常量引用,绑定到ci
auto &h = 42; //错误:不能为非常量引用绑定字面值
const auto &j = 42; //正确:可以为常量引用绑定字面值
七、decltype类型指示符
有时会遇到这种情况:希望从表达式的类型推断出要定义的变量的类型,但是不想用改表达式的值初始化变量。为了满足这一要求,c++11新标准引入了第二种类型说明符decltype,它的作用是选择并返回操作数的数据类型。在此过程中,编译器分析表达式并得到它的类型,却不实际计算表达式的值:
decltype(f()) sum = x; //sum的类型就是函数f的返回类型
编译器并不实际调用函数f,而是使用当调用发生时f的返回值类型作为sum的类型。
八、类内初始化
c++11新标准规定,可以为数据成员提供一个类内初始值(in-class initializer)。创建对象时,类内初始值将用于初始化数据成员,没有初始值的成员将被默认初始化。
九、范围for语句
如果想对string对象中的每个字符做点儿什么操作,目前最好的办法是使用C++11新标准提供的一种语句:范围for(range for)语句。这种语句遍历给定序列中的每个元素并对序列中的每个值执行某种操作,其语法形式是:
for(declaration : expression)
statement
其中,expression部分是一个对象,用于表示一个序列。因此string对象可以作为范围for语句中的expression部分。举个例子,我们可以使用范围for语句把string对象中的字符每行一个输出来
string str("some string");
//每行输出str中的一个字符。
for(auto c : str) //对于str中的每个字符
cout << c << endl; //输出当前字符,后面紧跟一个换行符
十、定义vector对象的vector
在早期的c++标准中,如果vector的元素还是vector(或者其他模板类型),必须在外层vector对象的右尖括号和其元素类型间添加一个空格,如应该写成
vector<vector<int> >而非vector<vector<int>>