C++中NULL和nullptr之间的区别.md

首先,C++中没有null,只有NULL和nullptr。

NULL引渡自C语言,一般由宏定义实现,而nullptr则是C++11的新增关键字。在C语言中,NULL被定义为(void*)0,而在C++语言中,NULL则被定义为整数0,编译器一般对其实际定义如下:

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

出现C++和C定义不一致的原因是,在C++中不允许(void*)类型进行隐式转换,例如:

1
2
3
4
5
char* a =" Hello";

void foo(void* p){}

foo(a);

以上这种调用方式在C++中是不允许的,在C++中指针必须有明确的类型定义。如上需使用foo((char*)a)才可以;但是将NULL定义为0带来的另一个问题是无法与整数的零区分。因为C++中允许有函数重载,所以可以试想如下函数定义情况:

1
2
3
void func(int data);

void func(char* data);

那么在传入NULL参数时,编译器将无法确定到底使用哪个函数定义,造成编译时错误。nullptr在C++11被引入用于解决这一问题,nullptr可以明确区分整型和指针类型,能够根据环境自动转换成相应的指针类型,但不会被转换为任何整型,所以不会造成参数传递错误。nullptr的一种实现方式如下:

1
2
3
4
5
6
7
const class nullptr_t{
public:
template<class T> inline operator T*() const{ return 0; }
template<class C, class T> inline operator T C::*() const { return 0; }
private:
void operator&() const;
} nullptr = {};

以上通过模板类和运算符重载的方式来对不同类型的指针进行实例化从而解决了(void*)指针带来参数类型不明的问题,另外由于nullptr是明确的指针类型,所以不会与整形变量相混淆。但nullptr仍然存在一定问题,例如:

1
2
3
void fun(char* p);

void fun(int* p);

在这种情况下存在对不同指针类型的函数重载,此时如果传入nullptr指针则仍然存在无法区分应实际调用哪个函数,这种情况下必须显示的指明参数类型。