关于0,NULL,nullptr的区别
NULL的定义,其定义在cstddef文件中如下:
#ifndef NULL
#define NULL
#endif
即NULL是用宏实现定义的空指针常量,在C 中的定义为 #define NULL((void *)0)
专门用来定义空指针的,C++ 为了兼容C中的老版本NULL(C是强类型语言,处理老版本的兼容问题时,必须强转,不然会报错),作了预处理操作,你可以将此看做定义如下:
#ifdef _cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
C++ 11 起 ,#define NULL 0改为了 #define NULL nullptr (nullptr虽然是个宏,你完全可以当作C的定义 (void *)0 个人感觉就是C++将0 和 (void *)0进行了区分,当然区分开了,多个类型检查,相当于细化了指针初始化的检查而已)
所以如果使用NULL 就和直接使用nullptr相同,当然C++建议使用零值整数字面量(如 int * p = 0),或为std::nullptr_t 类型纯右值 (如:int *p = nullptr),关键词nullptr 指代指针字面量。它是std::nullptr_t 类型的纯右值。存在从nullptr 到任何指针类型及任何指向成员指针类型的隐式转换。
上面提到的std::nullptr_t 在cstddef中的定义如下:
using nullptr_t = decltype(nullptr); (typedef void* nullptr_t;)
即空指针类型,有了这个空指针类型就可以将空指针作为函数参数来重载函数,此时需要注意,因NULL的定义过于复杂,其(void*)0的定义适合任意指针函数,所以重载时会出现重定义问题
void print(int *p)
{
cout << "hello int" << endl;
}
void print(double *p)
{
cout << "hello double" << endl;
}
void print(std::nullptr_t p) //这里的类型可以看做 void *
{
cout << "hello nullptr_t" << endl;
}
使用 int *p = NULL或nullptr时,调用print(p),直接调用第一个选项
使用 double *p = NULL或nullptr时,调用print(p),直接调用第二个选项
使用 std::nullptr_t p = nullptr时,调用print(p),直接调用第三个选项
没错你可能已经发现了,第三个重载只能调用std::nullptr_t,类型,不会去隐式的调用其他的类型,即便值相同。
如果开发为了快速好看好维护,初始化指针的时候还是尽量使用nullptr,不要使用0 或者 null,因为后两者在赋值的时候就相当于0值赋值,赋值给指针或者基本类型都没有问题,容易影响他人阅读代码。
如 int *p = 0;不如 int *p =NULL;看的直接
Int *p = NULL;又不如 int *p = nullptr;来的安全 (强类型检查本身就是一种安全的措施之一)。