应使用 nullptr 表示空指针,它是 c++11 起类型安全、语义明确的空指针字面量,类型为 std::nullptr_t,可隐式转换为任意指针类型但不转整数,避免重载歧义和类型推导错误。

用 nullptr 表示空指针,不是 NULL 或 0
在 C++11 及以后,nullptr 是唯一类型安全、语义明确的空指针字面量。它被设计为专门用于指针上下文,类型是 std::nullptr_t,能自动转换为任意指针类型,但不会隐式转成整数——这直接堵住了 NULL(通常定义为 0 或 ((void*)0))在函数重载时引发的歧义问题。
常见错误现象:
- 传 NULL 给一个接受 int 和 char* 的重载函数,编译器可能选错版本;
- auto p = NULL; 推导出 int 而非指针类型;
- 在模板中使用 NULL 可能导致类型推导失败。
- 始终用
nullptr初始化或比较指针:int* p = nullptr;、if (p == nullptr) - 不要用
0或NULL替代,哪怕代码“能编译” - 如果必须兼容 C++03 环境,再考虑宏或
0L,但这是例外,不是常规做法
nullptr 和 nullptr_t 的关系是什么
nullptr 是字面量,就像 42 或 "hello";它的类型是 std::nullptr_t,这是一个独立的、可空指针转换的空类型。它既不是整数,也不是指针,而是一个桥梁类型。
使用场景:
- 模板元编程中判断参数是否为空指针:std::is_same_v<decltype std::nullptr_t></decltype>;
- 自定义智能指针构造函数中区分 nullptr 和原始指针;
- 写泛型函数时避免对 nullptr 做算术操作(nullptr + 1 是非法的,而 0 + 1 合法,容易掩盖逻辑错误)。
-
sizeof(nullptr)是实现定义的,但和任意指针大小一致(通常是 4 或 8 字节) -
std::nullptr_t可以有值(只有一个值:就是nullptr),但不能取地址、不能赋值给非指针类型 - 它不参与用户定义的转换运算符调用,保证了类型安全性
为什么 if (p) 和 if (p != nullptr) 效果一样但推荐后者
两者在行为上等价:都检查指针是否非空。但写法意图不同。if (p) 是隐式转换(指针 → bool),而 if (p != nullptr) 是显式、对称的空指针比较,更易读、更一致,也更容易被静态分析工具识别。
容易踩的坑:
- if (p) 在启用 -Wzero-as-null-pointer-constant(Clang)或类似警告时,可能掩盖本该用 nullptr 的地方;
- 如果 p 是自定义类且重载了 operator bool(),if (p) 就不再是空指针检查了;
- 团队代码风格统一要求显式写出空状态,避免新人误读为“非零值判断”。
- 在纯指针上下文中,两种写法都合法,但团队规范应倾向
!= nullptr - 涉及智能指针(如
std::shared_ptr)时,if (sp)仍是惯用写法,因其operator bool()明确定义为“是否持有对象”,但原始指针不建议效仿 - 条件中混用(比如
if (p && q))可以接受,但单个判断建议显式
函数参数为指针时,怎么安全接收空值
空指针不是异常情况,而是有效输入。函数接口应明确支持 nullptr,并在文档或命名中体现可空性(例如用 opt_config、maybe_handler 等前缀)。关键不是“防崩溃”,而是“行为可预期”。
性能与兼容性影响:
- 检查 nullptr 几乎无开销(一条比较指令),现代 CPU 分支预测也很准;
- 不要为了“省一次判断”而用 assert(p),这会让调用方无法处理可空场景;
- 若函数逻辑天然不允许空(如 strlen),应使用引用类型或 gsl::not_null 等契约工具,而不是靠运行时检查。
- 入口处立即检查:
if (!ptr) return; // 或 throw std::invalid_argument - 避免在多处重复解引用前检查,把空值处理提前收口
- 返回指针的函数,若可能为空,务必在文档中声明,并让调用方知道需判
nullptr
空指针本身很简单,麻烦的是它常被当成“不该出现的东西”而绕着走——结果反而在边界路径里漏掉检查,或者用错类型机制。真正需要花力气的,是让每个指针变量从声明起就带着“它能不能是 nullptr”的明确契约。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











