<p>不能用 NULL 或 0 做空指针,因为它们是整数类型,导致重载解析错误(如调用 foo(int) 而非 foo(char))和模板推导失败(T 无法从 NULL 推导 T);C++11 引入的 nullptr 是 std::nullptr_t 类型,专用于指针上下文,安全且明确。</p>

为什么不能用 NULL 或 0 做空指针
因为它们本质是整数,编译器在重载解析或模板推导时可能选错函数。比如你写了两个重载:void foo(int) 和 void foo(char*),传 NULL 过去,老编译器大概率调用 foo(int) —— 它根本没当成指针用。
更隐蔽的问题是模板里:template<typename t> void bar(T*)</typename> 遇到 bar(NULL),T 无法推导成指针类型,直接编译失败。
-
NULL在多数头文件里定义为0或0L,不是指针类型 -
0是字面量整数,C++11 之前没有原生空指针常量概念 - 某些平台(如嵌入式)的
NULL可能被定义为(void*)0,但 C++ 禁止void*隐式转其他指针类型
nullptr 的类型和基本用法
nullptr 是 C++11 引入的关键字,类型是 std::nullptr_t,能隐式转换成任意原始指针类型,但不会转成整数。
它不占用内存,不参与算术运算,也不能取地址 —— 就是个纯标记。
立即学习“C++免费学习笔记(深入)”;
- 赋值给指针变量:
int* p = nullptr; - 函数参数传递:
func(nullptr);(自动匹配void*、int*等重载) - 比较操作安全:
if (p == nullptr)比if (!p)更明确,且不依赖隐式转换 - 注意:
nullptr不能用于非指针类型上下文,比如int x = nullptr;直接报错
和智能指针一起用要注意什么
std::shared_ptr 和 std::unique_ptr 都支持用 nullptr 构造或赋值,语义清晰,但别误以为它等价于默认构造。
-
std::shared_ptr<int> sp = nullptr;</int>→ 内部控制块为空,等价于std::shared_ptr<int>()</int> -
std::unique_ptr<int> up(nullptr);</int>→ 合法,但up.get()返回nullptr,解引用必崩 - 别写
if (sp == nullptr):虽然能编译,但推荐用if (!sp)或if (sp == nullptr)二者都行,前者更常见;后者在需要显式强调空指针语义时更稳妥 - 模板函数中接收
std::shared_ptr<t></t>参数时,传nullptr是完全合法的,不用额外特化
跨平台和旧代码迁移的坑
如果你还在维护 C++98/03 项目,或者要兼容 MSVC 2010 以前版本,nullptr 不可用 —— 但硬切 NULL 也不安全。
- 最低要求:编译器必须支持 C++11(GCC 4.6+、Clang 3.0+、MSVC 2010 SP1+)
- 宏兼容方案慎用:
#define nullptr __null(GCC)或#define nullptr 0都会倒退到老问题,不推荐 - 迁移时重点查三类地方:
NULL出现在模板实参位置、函数重载调用点、sizeof(NULL)类型探测逻辑 - 静态分析工具(如 clang-tidy)可配
modernize-use-nullptr自动替换,但需人工核对重载场景
最麻烦的其实是宏定义里藏的 NULL,比如 #define SAFE_DELETE(p) do { delete p; p = NULL; } while(0) —— 这种地方换 nullptr 后,p 类型必须是指针,否则编译不过。得先确认 p 的类型约束。










