因为0是int类型,重载时可能误匹配整型函数;nullptr是std::nullptr_t类型,只可转为指针,类型安全。例如foo(0)调用foo(int)而非foo(int*)。

为什么不能用 0 当空指针,而必须用 nullptr
因为 0 是整数字面量,类型是 int(或带符号整型),在函数重载场景下会优先匹配整型参数而非指针参数,导致意外调用错误的重载版本。而 nullptr 是类型安全的空指针常量,类型为 std::nullptr_t,只能隐式转换为任意指针类型,不会转成整数。
常见错误现象:
void foo(int) { cout << "int"; }
void foo(char*) { cout << "ptr"; }
foo(0); // 输出 "int",不是预期的 "ptr"
实操建议:
• 所有新代码中,指针初始化、比较、返回空值时一律用 nullptr
• 禁止用 NULL(它通常是 #define NULL 0 或 #define NULL ((void*)0),前者仍有重载歧义,后者在 C++ 中不合法)
• 若需兼容 C 接口(如 execl 等变参函数),仍可传 0,但这是特例,不是推荐做法
nullptr 在模板和泛型代码里为什么更可靠
模板推导无法区分 0 和指针语义,nullptr 则能明确表达“这是一个空指针”,让类型系统正确参与推导。
使用场景举例:
templatevoid bar(T* p);
bar(0); // T 被推导为 int,编译失败
bar(nullptr); // T 被正确推导为(例如)int,p 类型为 int*
实操建议:
• 模板函数/类中接收指针参数时,测试用例务必覆盖 nullptr,而非 0
• 使用 std::is_null_pointer_v 可在编译期检查是否为 nullptr 类型
• 注意:nullptr 不能用于算术运算(如 nullptr + 1),这反而是好事——暴露非法操作
C++98 到 C++11 的空指针常量演进关键节点
本质是语言从“用整数模拟空指针”走向“原生支持空指针类型”的过程。
关键事实:
• C++98/03:只有 0 和宏 NULL(通常定义为 0),无类型安全
• C++11:引入 nullptr 关键字,类型为 std::nullptr_t,可隐式转为任意指针类型,但不可转为整型
• C++14:nullptr 可用于 constexpr 上下文,且支持模板参数推导改进
• C++17:允许 if constexpr 中直接判断 nullptr 类型分支
兼容性影响:
• nullptr 在 C++11 及之后才可用,旧项目升级需确认标准版本(如 -std=c++11)
• nullptr 不是宏,不能被 #undef,也不受头文件包含顺序影响
• 跨语言接口(如 C 和 C++ 混合)中,C 头文件里的 NULL 定义不影响 C++ 文件中 nullptr 的行为
容易被忽略的细节:比较、sizeof 和模板偏特化中的 nullptr
很多人以为 nullptr 就是“更安全的 0”,其实它在底层语义和编译器处理上完全不同。
立即学习“C++免费学习笔记(深入)”;
注意事项:
• sizeof(nullptr) 是实现定义的(通常为 1 或指针大小),但绝不是 sizeof(int)
• nullptr == nullptr 为 true,但 nullptr 和任意非空指针比较结果未指定(实际为 false),不应依赖其大小关系
• 模板偏特化时,可以专门针对 std::nullptr_t 写特化版本:template struct is_ptr<:nullptr_t> : std::true_type {}
• nullptr 不能用于位运算(~nullptr 报错)、不能取地址(&nullptr 无效)、不能解引用(*nullptr 是未定义行为)
真正复杂的地方在于:你可能写了十年 C++,但第一次认真看 std::nullptr_t 的定义才发现它是个空类类型——这意味着它在 ABI 层面几乎零开销,却撑起了整个现代 C++ 的空指针语义体系。










