nullptr
nullptr 出现的目的是为了替代 NULL。在某种意义上来说,传统 C++ 会把 NULL、0 视为同一种东西,这取决于编译器如何定义 NULL,有些编译器会将 NULL 定义为 ((void*)0),有些则会直接将其定义为 0。
C++ 不允许直接将 void * 隐式转换到其他类型,但如果 NULL 被定义为 ((void*)0),那么当编译
char*ch=NULL;
时,NULL 只好被定义为 0。而这依然会产生问题,将导致了 C++ 中重载特性会发生混乱,考虑:
voidfoo(char *);
voidfoo(int);
对于这两个函数来说,如果 NULL 又被定义为了 0 那么 foo(NULL); 这个语句将会去调用 foo(int),从而导致代码违反直观。
voidfoo(char *);
voidfoo(int);
对于这两个函数来说,如果 NULL
又被定义为了 0
那么 foo(NULL); 这个语句将会去调用 foo(int),从而导致代码违反直观。
为了解决这个问题,C++11 引入了 nullptr 关键字,专门用来区分空指针、0。nullptr 的类型为 nullptr_t
,能够隐式的转换为任何指针或成员指针的类型,也能和他们进行相等或者不等的比较
constexpr
C++ 本身已经具备了常数表达式的概念,比如 1+2, 3*4 这种表达式总是会产生相同的下结果并且没有任何副作用。如果编译器能够在编译时就把这些表达式直接优化并植入到程序运行时,将能增加程序的性能。一个非常显著的例子就是在数组的定义阶段:
#define LEN 10
int len_foo() {
return 5;
}
int main() {
char arr_1[10];
char arr_2[LEN];
int len = 5;
char arr_3[len+5]; // 非法
const int len_2 = 10;
char arr_4[len_2+5]; // 合法
char arr_5[len_foo()+5]; // 非法
return 0;
}
在 C++11 之前,可以在常量表达式中使用的变量必须被声明为 const,在上面代码中,len_2 被定义成了常量,因此 len_2+5 是一个常量表达式,所以能够合法的分配一个数组;
而对于 arr_5 来说,C++98 之前的编译器无法得知 len_foo() 在运行期实际上是返回一个常数,这也就导致了非法的产生。
C++11 提供了 constexpr 让用户显式的声明函数或对象构造函数在编译器会成为常数,这个关键字明确的告诉编译器应该去验证 len_foo 在编译器就应该是一个常数。
类型自动推导auto和decltype
C++中每个变量的类型都需要明确定义,这实际上对我们进行快速编码没有任何帮助,尤其是当我们面对一大堆复杂的模板类型时,必须明确的指出变量的类型才能进行后续的编码,这不仅拖慢我们的开发效率,也让代码变得又臭又长。
可以使用auto和decltype关键字来进行变量的自适应
从前使用迭代器来进行vector的访问需要这么写
For(vector<int>::iterator it =vec.begin();it ! = vec.end();it++)
现在可以这么写
For(auto it = vec.begin();it ! =vec.end();it++)
还可以这么写
Auto i = 5;//i被推导为int
Auto i = new auto(10)//i被推导为int *类型
Auto变量不能用于函数参数,如果想要实现类似的功能,可以使用函数模板
比如int a(autoc,auto d){return 3;}无法通过编译
Auto不能用来推导数组类型,
比如autoaa[3]={1,2,3}
Int cc[3];
Auto aa = cc;//这里妄图使aa成为int *类型,其本质上仍然是数组
Decltype的使用
Decltype的出现能够弥补auto只能对变量进行类型推导
Decltype的使用方法和sizeof的使用方法类似
Decltype(表达式)
比如这么使用 auto a =1;
Auto b = 2;
Decltype(a + b) c;
Decltype可以当做类型使用,直接用来定义变量
对于某些模板函数而言,其返回类型不能确定,在一般情况下我们只能这样写:
Template<class R, class T, class Q>
R add(T a, Q b)
{return a + b;}
但是这样的代码是很“丑陋”的,因为你在使用add函数的时候,需要提前定义返回值的类型,当add里面的内容非常的复杂,返回值的类型是难以确定的
所以很容易就能想到以下写法:
Decltype(a + b) add(T a,Q b);
但是当程序运行到函数这里,a和b还没有定义,不能完成编译
为了解决这个问题,C++11引入了一个叫做返回类型后置的机制,写法如下:
Template<class T, class Q>
auto add(T a, Q b) -> decltype(a + b) {
return a + b;
}
但是C++14开始,函数能够具备返回值推导,因此下面的写法是正确的:
Template<class T, class Q>
auto add(T a, Q b) {
return a + b;
}