NULL 不类型安全,易导致重载二义、模板推导失败;nullptr 是 C++11 引入的 std::nullptr_t 字面量,只转指针类型,保障类型安全与编译期检查。
NULL 替代 nullptr
NULL 在 C++98/03 中本质是整数 0 或宏定义(如 #define NULL 0 或 #define NULL ((void*)0)),它不是类型安全的。当函数重载存在 void f(int) 和 void f(char*) 时,f(NULL) 会调用 f(int),而非预期的指针版本——这是最典型的二义性问题。
而 nullptr 是 C++11 引入的字面量,类型为 std::nullptr_t,可隐式转换为任意指针类型,但不会转换为整数类型。因此 f(nullptr) 必定匹配指针重载版本。
NULL 可能被编译器当作 int,导致模板推导失败(如 tem
plate void g(T*) 接收 NULL 时推导为 g)nullptr 在模板中能正确推导为指针类型,且支持 auto 推导: auto p = nullptr; → p 类型是 std::nullptr_t
NULL 定义依赖于 __cplusplus 宏,跨平台或混合 C/C++ 编译时行为不一致nullptr 的类型和隐式转换规则nullptr 不是关键字而是字面量,其类型是唯一的 std::nullptr_t,定义在 中。它只能隐式转换为指针类型(包括成员指针),不能转为 bool、int 或用户自定义类型(除非你显式提供接受 std::nullptr_t 的构造函数)。
int* p = nullptr;、void (A::*mp)() = nullptr;、if (p == nullptr)
int x = nullptr;(编译错误)、bool b = nullptr;(需写成 bool b = (p != nullptr);)nullptr 和 0 在比较中等价,但语义完全不同;nullptr == 0 合法,但这是靠指针与整数的比较规则,不推荐这样写已有代码大量使用 NULL 时,不能简单全局替换为 nullptr,尤其当涉及宏、函数参数或模板特化时。
NULL:如 func(NULL) → func(nullptr),这是最安全、收益最大的改动nullptr(如 #define SAFE_DELETE(p) do { delete p; p = nullptr; } while(0) 是 OK 的;但若宏用于 C 头文件则仍需保留 NULL)NULL 做默认参数(如 template void foo(T* p = NULL) ),应改为 = nullptr,否则实例化时可能因 T 非指针而编译失败const char* 或 void*,传 nullptr 没问题;但若接口是 C 风格(如 some_c_api(int flag, void* data)),且文档说 “data 为 NULL 表示忽略”,那传 nullptr 依然合法——因为 nullptr 可转为任意指针类型真正出问题的地方往往不在主干逻辑,而在细节交互处。
std::function 绑定空函数对象时:std::function f = nullptr; 合法,但 f() 会抛 std::bad_function_call;而 f = NULL 可能因类型不匹配编译失败constexpr 上下文中:constexpr int* p = nullptr; 合法;但 constexpr int* q = NULL; 在某些老编译器上可能不被接受(因 NULL 展开为非字面量表达式)MyClass() : ptr(NULL) {} 应改为 : ptr(nullptr),否则若 ptr 是智能指针(如 std::unique_ptr),用 NULL 初始化可能触发隐式 int 构造,造成未定义行为最麻烦的不是语法错误,而是那些“看起来能过编译、运行也不报错、但逻辑悄悄走歪”的情况——比如重载选错、模板实例化异常、或者跨模块 ABI 不一致。用 nullptr 就是把这类隐患从运行时提前到编译期暴露出来。