手机版
你好,游客 登录 注册
背景:
阅读新闻

C++11 之 nullptr

[日期:2016-04-28] 来源:Linux社区  作者:xinxue [字体: ]

C++11 中, nullptr 是空指针,可用来给(指向任意对象类型的)指针进行赋值

广义整型 (integral types) = char, short, int, long, long longnd and their unsigned counterparts, and bool, wchar_t, char16_t, and char32_

1  调用重载函数

  0 在 C++ 中,被首先视为 int 型。NULL 在 C++ 中,首先视为广义整型 (integral types),至于具体是 int,long 或是其它,要视相应的情况而定

  下面三个函数,因为形参类型的不同,构成重载函数。如果各传递三个不同的实参,来选择调用哪个函数,则会出现如下问题:

// three overloads of f
void f(int);   
void f(bool);
void f(void*);

f(0);      // calls f(int), not f(void*)
f(NULL);    // might not compile, but typically calls f(int). Never calls f(void*)
f(nullptr); // calls f(void*) overload

1) C++ 视 0 首先为 int 型,因此,调用 f(0) 即调用 f(int)

2) NULL 的情况复杂些,但 C++ 仍然视其首先为广义整型(integral tyoes)。假如 NULL 被定义为普通的 0,则调用 f(int)。

  如果 NULL 被定义成 0L,则 long -> int, long -> bool, 0L -> void*, 这三种情况都是合法的,此时,编译器会报错

3) 使用 nullptr,则不会有重载函数调用模糊的问题

    - nullptr 不属于广义整型,也不是普通意义上的指针

    - nullptr 的实际类型是 std::nullptr_t,它能够隐式的转换成所有的原始指针类型,故可将其视为一个指向所有类型的指针

2  代码清晰

  使用 nullptr 来代替 0 或 NULL,能够显著提高代码的清晰度,如下例所示:

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

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

  使用 0 与 result 作比较,则第一眼很难确定 findRecord 的返回值类型,因为可能是广义整型,也可能是指针类型

  而使用 nullptr,却可以清楚地知道 findRecord 的返回值,必定是一个指针类型

3  模板函数

  当程序中涉及模板(template)时,使用 nullptr 的好处更加明显,如下所示:

// call these only when the appropriate mutex is locked
int f1(std::shared_ptr<Widget> spw);
double f2(std::unique_ptr<Widget> upw);
bool f3(Widget* pw);

// calling code that wants to pass null pointers
std::mutex f1m, f2m, f3m; // mutexes for f1, f2, and f3
using MuxGuard = std::lock_guard<std::mutex>;

...
{
    MuxGuard g(f1m);        // lock mutex for f1
    auto result = f1(0);    // pass 0 as null ptr to f1
}                          // unlock mutex

...
{
    MuxGuard g(f2m);        // lock mutex for f2
    auto result = f2(NULL); // pass NULL as null ptr to f2
}                          // unlock mutex

...
{
    MuxGuard g(f3m);            // lock mutex for f3
    auto result = f3(nullptr);  // pass nullptr as null ptr to f3
}                          // unlock mutex           

  lock mutex -> call function -> unlock mutex,这个模式在程序中重复了三次,要想避免这种重复,可用一个模板函数代替之

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

  最后,调用该模板函数

auto result1 = lockAndCall(f1, f1m, 0);          // error!
...
auto result2 = lockAndCall(f2, f2m, NULL);      // error!
...
auto result3 = lockAndCall(f3, f3m, nullptr);    // fine

  当 0 作为实参传递给 lockAndCall 函数时,其被 C++ 推断为 int 型,这与 f1 所期望的 std::shared_ptr<Widget> 型参数明显不符,因此出现报错

  同理,NULL 与 f2 期望的 std::unique_ptr<Widget> 型参数也不符合

  nullptr,作为 ptr 传给 f1 或 f2 时,被推断为 std::nullptr_t ; 作为 ptr 传给 f3 时,std::nullptr_t 会隐式的转换成 Widget*,确保了参数类型的一致

小结:

1)  prefer nullptr to 0 and NULL

2)  avoid overloading on integral and pointer types

参考资料

 <Effective Modern C++> Item 8

 <C++ Programming Language> "integral types"

本文永久更新链接地址http://www.linuxidc.com/Linux/2016-04/130794.htm

linux
相关资讯       C++11  nullptr 
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数

       

评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款