参考《深入理解C++11》
NULL是一个宏定义,在传统C头文件stddef.h中定义如下:
#undef NULL #ifdef(__cplusplus) #define NULL 0 #else #define NULL ((void *)0) #endif
可以看到,NULL可能被定义为字面常量0,或者定义为无类型指针(void*)常量。这就使得在使用NULL时有些问题:
在main函数中,f(NULL)调用的起始是第二个函数,因为在C++98中,字面常量0具有二义性:既可以是一个整型,也可以是一个无类型指针(void*)。如果想要调用f(char*)的话,需要对字面常量0进行强制类型转换:(void*)0 然后再调用,否则编译器总会优先把0看做一个整型常量。
nullptr_t的定义:头文件:<cstddef>
typedef decltype(nullptr) nullptr_t;
使用nullptr_t时必须包含头文件:<cstddef>,但是使用nullptr时则不用,因为nullptr是关键字。nullptr是有类型的,且仅可以被隐式转化为指针类型,在编写C++11代码时,使用nullptr替换NULL将使得代码更健壮。
- nullptr:指针空值常量
- nullptr_t:指针空值类型,也就是nullptr的类型,见上面的定义
nullptr_t注意事项:
示例代码:
char* cp = nullptr; //不可转换为整型,而任何类型也不能转换为nullptr_t //以下代码不能通过编译 //int n1 = nullptr; //int n2 = reinterpret_cast<int>(nullptr); //nullptr与nullptr_t类型变量可以作比较 //当使用 == <= >=符号比较时返回true nullptr_t nptr; if (nptr == nullptr) { cout << "nullptr_t nptr == nullptr" << endl; } else { cout << "nullptr_t nptr != nullptr" << endl; } if (nptr < nullptr) cout << "nullptr_t nptr < nullptr" << endl; else cout << "nullptr_t nptr !< nullptr" << endl; //不能转换为整型或bool类型,以下代码不能通过编译 //if(0 == nullptr) //if(nullptr) //不能进行算术运算,以下代码不能通过编译 //nullptr += 1; //nullptr *5; //以下操作均可正常运行 size_t size1 = sizeof(nullptr); typeid(nullptr); throw(nullptr);
注:如果上述代码注释部分能通过编译,可能是编译器版本不够新,在C++11中不允许上述注释代码。
虽然nullptr_t看起来像是个指针类型,但是在把nullptr_t应用于模板中时,模板会把它作为一个普通的类型来进行推导,并不会将其视为T*指针。
template<typename T> void g(T* t){} template<typename T> void h(T t){} int main(int argc, char *argv[]) { g(nullptr); //编译失败,nullptr的类型是nullptr_t,而不是指针 g((float*) nullptr);//推导出T=float h(0); //推导出T=int h(nullptr); //推导出T=nullptr_t h((float*)nullptr); //推导出T=float* }