C++ 中 NULL 与 nullptr 有什么区别?
一、背景和起源
NULL
来源:C 语言。
本质:一个宏,代表数字
0
。示例(大多数系统的定义):
#define NULL 0
nullptr
引入版本:C++11。
本质:一个关键字,表示空指针的专用字面量。
类型:
std::nullptr_t
,是一个专门为空指针定义的类型。
二、类型层面上的根本区别
NULL
—— 是个整数常量(int)
void func(int);
void func(char*);func(NULL); // NULL是0,本质是int,调用func(int),指针重载无效!
它不是指针类型,而是整数0,只有在编译器做隐式转换时,才“看起来像”是空指针。
nullptr
—— 是真正的空指针类型
void func(int);
void func(char*);func(nullptr); // 正确调用func(char*),因为nullptr是指针类型
它的类型就是 std::nullptr_t
,只会被转换为任意类型的指针,而不会被转换为整数。
三、重载函数中的区别 —— 最直观的例子
示例一:NULL
引发歧义
void foo(int x) { std::cout << "int\n"; }
void foo(char* s) { std::cout << "pointer\n"; }foo(NULL); // 输出 "int",不是你预期的 "pointer"
解释:
NULL
是0
,类型是int
,因此匹配的是foo(int)
。
示例二:nullptr
正确解析
void foo(int x) { std::cout << "int\n"; }
void foo(char* s) { std::cout << "pointer\n"; }foo(nullptr); // 输出 "pointer",因为nullptr只能当作指针
解释:
nullptr
只能转换为char*
,匹配foo(char*)
,避免了歧义。
四、模板编程中的区别
在模板中,如果你传的是 NULL
,编译器可能会以为你传的是一个整数,而不是指针。
template<typename T>
void test(T val) {std::cout << typeid(T).name() << std::endl;
}test(NULL); // T 被推导为 int
test(nullptr); // T 被推导为 std::nullptr_t
这会影响你函数模板的行为,甚至可能报错。
nullptr
是 C++ 专门设计的空指针类型,安全、清晰、无歧义;NULL
是历史遗留的整数宏,容易出错,已被淘汰。