14.4 空指针 nullptr
在老版本的 C 和 C++98 代码汇总,你一定见过无数次用大写的 NULL 来赋给一个指针表示它是空的。
int* p = NULL;但这其实是一个隐伏了数十年的设计漏洞。在 C++11 中,请彻底忘掉并且永远不要再写 NULL,使用新关键字 nullptr 取而代之。
NULL 造成了什么问题?
Section titled “NULL 造成了什么问题?”因为 C++ 不像 C 那样允许 void* 随意隐式转换为任意别的类型的指针,所以在 C++ 源码早期的标准头文件中,NULL 被暴力无情地使用预处理器宏定义为了一个整数的零:
#define NULL 0也就是说,**你自以为的“空指针”,在编译器眼里只是一串冷冰冰的整数 0 字面常量。**这就引发了类型重载匹配时的超级灾难。
请看下例:
#include <iostream>
void printAction(int number) { std::cout << "我收到一个整数。\n";}
void printAction(int* ptr) { std::cout << "我收到一个指针。\n";}
int main() { printAction(0); // 毫无疑问,调用的上面的整型重载版 printAction(NULL); // 糟糕!本意想传空指针的你调用的依然是上面的整型重载版!}原本你应该期望传 NULL 进去时匹配到指针那个重载签名,结果编译器死活认准了 NULL 被宏展开为了 0,于是跑去了第一个重载函数里去了。
救世主:nullptr
Section titled “救世主:nullptr”C++11 引入的 nullptr 并不是一个宏,它是一个全新的关键字,其类型是 std::nullptr_t。
你可以这样理解它:
- 它只能被转化为任意类型的裸指针或者智能指针,或者与各种指针发生比较(
ptr == nullptr)。 - 它绝对不能隐式转换为任何整型类型的值。
有了它,重载函数就可以被正确匹配了!
int main() { printAction(0); // 匹配 printAction(int) printAction(nullptr); // 完美匹配真正接受空指针参数的 printAction(int*)}现代 C++ 规范推荐的使用准则
Section titled “现代 C++ 规范推荐的使用准则”- 如果是表示一个数字,写
0。 - 如果是表示字符串的结束符,或者想赋值单个字符置空,写
'\0'。 - 如果是代表没有指向任何内存的指针标志,使用
nullptr。
永远不要将三者混用,永远告别 NULL!