首页 > 代码库 > C++11中的指针空值nullptr

C++11中的指针空值nullptr

时间: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的地址通常也没有意义。