Effective Modern C++ Item 8 优先选用nullptr,而非0或NULL

字面常量是0的型别是int,而非指针。而NULL的型别不确定,但不具有指针型别。

这样的问题可以会出现在以下代码中:

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是可以匹配上的。

nullptr 不具备整型型别,实际上,它也不具备指针型别,但它可以隐式转换到所有裸指针型别。

以上优点还并不是nullptr的唯一优点,它还可以让代码更加清晰:

nullptr使代码更清晰

auto result = findRecord(/* 实参 */);
if (result == 0){
    ...
}

auto result = findRecord(/* 实参 */);
if (result == nullptr){
    ...
}

上述第一种写法会有多义性,导致无法明了result的型别,但是第二种写法一眼可以看出result是个指针。

更大的优势在于nullptr用于模板

int f1(std::shared_ptr<Widget> spw);
double f2(std::unique_ptr<Widget> upw);
bool f3(Widget* pw);
//调用示例
std::mutex f1m, f2m, f3m;

using MuxGurad = std::lock_guard<std::mutex>;
...
{
    MuxGuard g(f1m);
    auto result = f1(0);
}
...
{
    MuxGuard g(f2m);
    auto result = f2(NULL);
}
...
{
    MuxGuard g(f3m);
    auto result = f3(nullptr);
}
...

以上代码就能运作,这时候,看到重复的代码流程,我们想写模板的思想就产生出来了,一定要泛化一个呗。于是乎,来了如下的代码:

//C++11
template<typename FuncType, typename MuxType, typename PtrType>
auto lockAndCall(FuncType func, MuxType& mutex, PtrType ptr)->decltype(func(ptr))
{
    MuxGuard g(mutex);
    return func(ptr);
}

//C++14
template<typename FuncType, typename MuxType, typename PtrType>
decltype(auto) lockAndCall(FuncType func, MuxType& mutex, PtrType ptr)
{
    MuxGuard g(mutex);
    return func(ptr);
}

//调用示例:
auto result1 = lockAndCall(f1, f1m, 0);         //错误!
auto result2 = lockAndCall(f2, f2m, NULL);      //错误!
auto result3 = lockAndCall(f3, f3m, nullptr);   //没问题!

result1无法编译的问题是因为0PtrType推导为int,那么func对应的传入就为int,与f1期望的std::shared_ptr不兼容。而result2的错误与result1类似。而由于nullptr由于肯定不会被解析为int从而免疫了这种问题。

要点速记
1. 相对于0或NULL,优先选用nullptr。
2. 避免在整型和指针型别之间重载。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值