参考《深入理解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注意事项:
示例代码:
扫描二维码关注公众号,回复:
15836397 查看本文章
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*
}