NULLptr是c++11起唯一推荐的空指针字面量;NULL本质是整型常量0或0L,易导致重载歧义、模板推导失败,并触发编译器警告。

在 C++11 及之后的版本中,nullptr 是唯一推荐的空指针字面量;用 NULL 或整数字面量(如 0)表示空指针,不仅语义模糊,还可能引发函数重载歧义和模板推导错误。
为什么不能继续用 NULL
NULL 在绝大多数标准库实现中被定义为 0 或 0L(即整型常量),不是指针类型。这会导致几个典型问题:
- 传给重载函数时可能意外匹配
int版本而非void*版本 - 在模板中(如
std::function构造、std::make_unique)无法正确推导指针类型 - 静态分析工具或编译器(如 Clang 的
-Wzero-as-null-pointer-constant)会发出警告
void foo(int x) { std::cout << "intn"; } void foo(char* p) { std::cout << "ptrn"; } foo(NULL); // 输出 "int" —— 不是你想要的! foo(nullptr); // 输出 "ptr" —— 正确绑定到指针重载
nullptr 的类型和使用限制
nullptr 的类型是 std::nullptr_t,它可隐式转换为任意原始指针类型(int*、void* 等),但不能转换为整数类型(如 int、long),也不能赋值给非指针类型变量。
- ✅ 合法:
int* p = nullptr;、void* v = nullptr;、auto x = nullptr;(x 类型为std::nullptr_t) - ❌ 非法:
int i = nullptr;、if (nullptr == 42) {...}、std::vectorv = {nullptr}; - ⚠️ 注意:
nullptr不能用于算术运算(nullptr + 1编译失败),也不能解引用(*nullptr是未定义行为)
在模板和智能指针中必须用 nullptr
现代 C++ 中,std::unique_ptr、std::shared_ptr 和容器算法(如 std::lower_bound)都依赖类型精确性。NULL 会破坏模板参数推导。
立即学习“C++免费学习笔记(深入)”;
std::unique_ptr p1 = nullptr; // ✅ OK // std::unique_ptr p2 = NULL; // ❌ error: no viable conversion std::map m; m.find(nullptr); // ❌ 编译失败:key_type 是 string,不能用 nullptr 比较 // 但若你写成 m.find(std::string()), 就是另一回事了 —— 这里凸显的是类型安全,不是 nullptr 的错
更关键的是,像 std::Thread 构造函数接受可调用对象,若误传 NULL,可能被当作 int 而非空函数指针,导致静默错误。
跨平台与兼容性提醒
如果你的项目仍需支持 C++98/03 编译器(如极老的嵌入式工具链),nullptr 不可用,此时只能用 0 并配合注释说明意图。但只要能用 C++11,就绝不该再定义自己的 NULL 宏或沿用旧头文件里的 #define NULL 0。
另外,nullptr 不是宏,不参与预处理;它是一个关键字,因此 sizeof(nullptr) 是合法的(通常等于 sizeof(void*)),而 sizeof(NULL) 结果取决于其定义(可能是 sizeof(int))。