时间:2014.05.07
地点:基地
-----------------------------------------------------------------------------
一、为什么要有指针空值nullptr
在良好的编码习惯中,声明一个指针并对其进行初始化非常重要,未初始化的悬挂指针常导致一些难以调试的错误。往常,我们常这样初始化指针变量:
int* my_ptr1=0; int* my_ptr2=NULL;
但我们知道,NULL其实是一个宏定义,字面常量为0,即上述两种方式本质上是一样的。于是,这样就有了一些麻烦,比如函数重载时,我们定义了如下两个版本的函数:
#include<iostream> using namespace std; void f(char* c) { cout << "invoke f(char* c)" << endl; } void f(int i) { cout << "invoke f(int)" << endl; } int main() { f(0); f(NULL); f((char*)0); f(nullptr); return EXIT_SUCCESS; }
结果如下:
可见,f(NULL)并没有调用想要的指针版本,而是调用了f(int)版本,这是因为NULL被定义为0,编译器总是优先把0视为一个整型常量造成的。0在C++98中是有二义性的,编译器首先解释它是一个整型常量,其次是一个无类型指针(void*)。
-----------------------------------------------------------------------------
二、问题的解决
C++11中,首先为了兼容性考虑并没消除0的二义性,但给出了一种新的方案,使用指针空值nullptr去初始化指针。指针空值的类型被命名为nullptr_t。它是这么来的:
typedef decltype(nullptr) nullptr_t;
充分利用了decltype 。即nullptr也是有类型的。且仅可以被隐式转化为指针类型。于是f(nullptr)会调用f(char*)版本。这样用户也就能表达自己的意图了。
-----------------------------------------------------------------------------
三、类型nullptr_t
上面我们已经知道nullptr的类型为nullptr_t,我们再看看这种类型有什么特点
1.nullptr_t是一种内置数据内型
2.nullptr_t类型 数据可以隐式转换为任意一种指针类型,但无论你想什么方式都不能转换为非指针类型。
3.nullptr_t类型数据不可用于算术运算
4.nullptr_t类型数据可以用于同类型数据之间进行关系运算。
所以诸如:
if(nullptr); if(nullptr==0);
是不能编译通过的。
值得注意的是nullptr_t看起来像个指针类型,但其实不是的,它就是nullptr_t这样一种类型,比如在模板中就不能当做是一种指针类型传递给模板参数了,模板是推导不出它的具体类型的,必须显式转换:
template<typename T>void g(T* T){} ...... g(nullptr); //编译错误 g((float*)nullptr); //可推导出T为float
另外
sizeof(nullptr_t)==sizeof(void*)
即nullptr)_t所占的内存空间大小和void*相同,但他们两者的内涵是不一样的。nullptr是一个编译时期的常量,能为编译器识别。而(void*)0只是一个强制转换表达式,返回一个void* 指针类型的数据而已。而且nullptr到任何指针的转换都是隐式的。而且我们不要对nullptr进行去地址操作,因为它是一个右值常量,取nullptr的地址通常也没有意义。
C++11中的指针空值nullptr,布布扣,bubuko.com