C++中NULL本质是整数0,非指针类型,易导致函数重载错误;应使用C++11引入的类型安全关键字nullptr,它为std::nullptr_t类型,可隐式转换为任意指针但不转整数,支持正确重载、模板推导和显式空指针比较。

NULL 在 C++ 中本质是整数 0,不是指针类型
很多老代码里写 int* p = NULL;,看着没问题,但编译器其实把它当成了 int* p = 0;。这在函数重载场景下会出问题:void foo(int) 和 void foo(char*) 同时存在时,foo(NULL) 会意外调用 foo(int),而不是你期望的指针版本。
原因在于:C++ 标准规定 NULL 是实现定义的宏,常见实现是 #define NULL 0 或 #define NULL 0L,始终是整型常量。
- 不推荐在 C++11 及以后使用
NULL表示空指针 - 若需兼容旧代码,确保头文件中未自行重定义
NULL -
NULL在 C 头文件(如)中定义,C++ 中应优先用标准空指针字面量
nullptr 是类型安全的空指针字面量
nullptr 是 C++11 引入的关键字,类型为 std::nullptr_t,能隐式转换为任意指针类型,但不会转成整数类型。这意味着它能正确参与函数重载、模板推导和 auto 类型推导。
例如:auto p = nullptr; 推导出 std::nullptr_t,而 auto q = NULL; 推导出 int —— 这直接影响后续赋值和比较行为。
立即学习“C++免费学习笔记(深入)”;
- 所有新代码必须用
nullptr替代NULL初始化或比较指针 - 不能对
nullptr执行算术运算(如nullptr + 1),编译直接报错,比运行时崩溃更早暴露问题 - 与
sizeof、typeid等操作符配合良好,语义清晰
判断空指针时避免隐式转换陷阱
写 if (p == nullptr) 是安全的;但写 if (p == 0) 或 if (!p) 虽然通常可行,却隐藏了类型风险。尤其在模板或泛型代码中,!p 可能触发用户自定义的 operator!,而非指针判空逻辑。
更隐蔽的问题出现在容器查找中:比如 std::map,用 m.find(0) 会因类型不匹配导致编译失败(0 是 int,不是 int*),而 m.find(nullptr) 可行。
- 统一用
p == nullptr或p != nullptr做显式空指针比较 - 禁用
if (p)/if (!p)风格(除非团队明确约定且静态检查覆盖) - 在模板参数、容器键类型、SFINAE 场景下,
nullptr是唯一可安全传递的空指针字面量
跨平台和遗留系统中的实际妥协点
极少数嵌入式编译器(如某些 ARM GCC 4.7 旧版本)或严格 C++03 环境不支持 nullptr。此时不应退回到 NULL,而应采用兼容性封装:
#ifdef __cplusplus11
#define SAFE_NULLPTR nullptr
#else
#define SAFE_NULLPTR 0
#endif但注意:这种宏仅用于初始化(int* p = SAFE_NULLPTR;),不可用于比较或模板实参——后者在 C++03 下本就不支持泛型空指针语义。
- 真正需要 C++03 兼容时,优先升级工具链,而非妥协语义
- 禁止在头文件中无条件
#define NULL nullptr,会破坏 C 头文件包含行为 - 第三方库若内部用
NULL,无需修改;但你的新代码与之交互时,仍应传nullptr(只要接口接受指针类型)
最易被忽略的是:即使用了 nullptr,也不能替代对指针生命周期的管理。悬空指针、释放后使用、多线程竞态等问题,nullptr 一个都拦不住——它只解决“怎么写空”这个语法层问题,不解决“什么时候该为空”这个逻辑层问题。










