本文主要涉及, nullptr
关键字(其实是个对象, 或者常量)以及std::nullptr_t
类型, 以及为什么要去使用它.
NULL
NULL是C, C++03或者98中使用最多的,
但是C++和C的定义不一样, 在<cstdlib>
中, 其定义如下:
1 |
之所以这样定义的原因,是因为在C语言中,允许 void*
类型隐式转换为任意指针类型,
而C++中不允许这样的强制类型转换,但是可以为任意类型的指针赋0值.
因此,在C++中将NULL 定义为0.
简单说: C++允许你用
void*
这样的泛指针接收任何类型的指针(一般是安全的, 在分配器里面用的很多), 但是不允许(void*)强制类型转换为具体的指针, 不安全;
所以啊, 只有0代替void*
了
NULL(预处理)定义为0, 显然更好, 更加直观.
nullptr
nullptr 是 nullptr_t 类型的常量,nullptr
来处理转换安全:
- 该类型定义了转到任意指针类型的转换操作符
- 不允许该类型的对象转换到非指针类型
写C++程序, 应该用
nullptr
代替0或者NULL 赋值给指针, C++11标准提倡的.
最简单的例子, 下面有两个重载:
1 | void f(int); |
那么无论f(0)
还是f(NULL)
都会调用f(int)
, 这个时候f(nullptr)
才会调用f(void*)
.
std::nullptr_t
<cstddef>
定义了一个std::nullptr_t
类型, 其定义如下:
1 | typedef decltype(nullptr) nullptr_t; |
nullptr准确来说, 是nullptr_t
类型的常量, nullptr_t
定义如下:
大致代码如下:
1 | class nullptr_t |
模板类型推断
为什么非要使用
nullptr
?
事实上,最迫使你使用nullptr代替0和NULL的原因是,模板类型推断会为0和NULL推断出“错误”的类型当你想要一个空指针时。有了nullptr,模板就不会引起什么问题了。
再想想nullptr不受重载函数选择策略影响,而0和NULL却容易受到影响。所以,当你要说明空指针时,用nullptr,而不是0或者NULL。
请看下面的例子: (lockAndCall
是有指针和整数参数重载的函数)
1 | auto result1 = lockAndCall(f1, f1m, 0); // 错误 |
怎么用
具体的使用看你的场景, 最多的应该是函数指针的场景, 那么声明的时候就可以做
1 | int (A::*pmf)()=nullptr; //指向成员函数的指针 |
或者检查对象是否为空, 可以这样:
1 | const char *pc=str.c_str(); //data pointers |
总而言之, 原来用NULL的地方, 换成nullptr就行啦.
若我偏不用
实际上, 最好还是使用nullptr, 不用的话, 就我知道的范围, 只要你能避免以下情况即可
避免整数类型与指针类型之间的函数重载
避免使用自动类型推断, 比如auto