条款8:优先考虑nullptr而非0和NULL
nullptr 更安全,避免重载解析歧义,推荐取代 0/NULL。
条款8:优先考虑nullptr而非0和NULL
条款 8:优先考虑 nullptr 而非 0 和 NULL
原因一:0 和 NULL 本质是整型,不是指针
表达式 | 实际类型 |
---|---|
0 | int |
NULL | 实现相关,通常是 int 或 long ,但不是指针类型 |
nullptr | std::nullptr_t ,可以隐式转换为任意类型的指针 |
原因二:函数重载中容易选错
1
2
3
4
5
6
7
void f(int);
void f(bool);
void f(void*);
f(0); // 调用 f(int),不是你想的 f(void*)
f(NULL); // 一般调用 f(int),也不会调用 f(void*)
f(nullptr); // ✅ 正确调用 f(void*)
nullptr
避免了因为整型优先级导致的错误重载决议。
原因三:更明确的语义
1
2
3
auto result = findRecord(...);
if (result == 0) // ❌ 不知道 result 是 int 还是指针
if (result == nullptr) // ✅ 明确:result 是指针类型
nullptr
让代码更具可读性和意图表达性。
原因四:模板参数推导中的正确行为
模板定义:
1
2
3
4
5
template<typename Func, typename Mutex, typename Ptr>
auto lockAndCall(Func func, Mutex& mtx, Ptr ptr) -> decltype(func(ptr)) {
std::lock_guard<Mutex> g(mtx);
return func(ptr);
}
三种调用:
1
2
3
lockAndCall(f1, m1, 0); // ❌ 0 推导为 int,类型错误
lockAndCall(f2, m2, NULL); // ❌ NULL 也被推导为整型,类型错误
lockAndCall(f3, m3, nullptr); // ✅ 推导为 std::nullptr_t,可转换为任意指针
nullptr
是模板友好型空指针常量,不会因类型推导错误导致编译失败。
nullptr
的类型特性
- 类型:
std::nullptr_t
- 能隐式转换为任意指针类型
- 不能转换为整数类型,因此不会误选
int
重载版本
总结
推荐:
- 使用
nullptr
表示空指针。 - 尤其在函数重载、模板调用、自动类型推导 (
auto
) 场景下。
避免:
0
、NULL
表示空指针:容易误选重载、类型推导错误。- 同时重载
int
和pointer
类型时传入0
/NULL
。
本文由作者按照 CC BY 4.0 进行授权