在c++11之前,表示空指针的方法都存在问题,虽然可以用NULL来表示,但问题也不少。

C的NULL

在C语言中,我们使用NULL表示空指针,也就是我们可以写如下代码:

1
2
int *i = NULL;
foo_t *f = NULL;

实际上在C语言中,NULL通常被定义为如下:

1
#define NULL ((void *)0)

也就是说NULL实际上是一个void *的指针,然后把void *指针赋值给int *foo_t *的指针的时候,隐式转换成相应的类型。

C++的NULL

但是在C++编译器来编译的话是要出错的,因为C++是强类型的,void *是不能隐式转换成其他指针类型的,所以通常情况下,编译器提供的头文件会这样定义NULL:

1
2
3
4
5
#ifdef __cplusplus 
#define NULL 0
#else
#define NULL ((void *)0)
#endif

因为C++中不能将void *类型的指针隐式转换成其他指针类型,而又为了解决空指针的问题,所以C++中引入0来表示空指针(注:0表示,还是有缺陷不完美),这样就有了类似上面的代码来定义NULL。实际上C++的书都会推荐说C++中更习惯使用0来表示空指针而不是NULL,尽管NULLC++编译器下就是0。

假设有如下的函数定义:

1
2
3
4
5
6
7
8
void bar(sometype1 a, sometype2 *b)
{
do something...
}
void bar(sometype1 a, int i)
{
do something...
}

在调用时,bar(a, NULL)这样的语句就可能造成逻辑上的问题,代码的本意是调用第一个函数,实际上是调用了第2个函数。因为NULL就是0,一个整型。 这个代码上的错误很容易忽略,因为NULL不够“明显”,而这里如果是使用0来表示空指针,那就会够“明显”,因为0是空指针,它更是一个整形常量。在C++中,使用0来做为空指针会比使用NULL来做空指针会让你更加警觉。

C++ 11的nullptr

上面我们说明了0比NULL可以让我们更加警觉,但是我们并没有避免这个问题。这个时候C++ 11的nullptr就很好的解决了这个问题,我们在C++ 11中使用nullptr来表示空指针。这样一切需要空指针的地方,我们都使用nullptr。

混合使用场景的解决方案

新的代码中我们可以用nullptr来表示空指针,但是在维护老的代码时,我们可以将部分维护过的代码中NULL替换成nullptr吗?答案是肯定的。nullptr和NULL都表示逻辑上的空指针,只是NULL还有副作用而已。使用到空指针的地方基本上都是判断语句中,使用时如下的2种场景都是ok的。

场景一:先用NULL给指针赋值,然后用nullptr来判断,是ok的。比如:

1
2
3
4
5
int* p = NULL;
if (p == nullptr)
{
printf("p is null\n");
}

场景二:先用nullptr给指针赋值,然后用NULL来判断,是ok的,比如:

1
2
3
4
5
int* p = nullptr;
if (p == NULL)
{
printf("p is null\n");
}