C++11 nullptr与nullptr_t

  参考《深入理解C++11》

  NULL是一个宏定义,在传统C头文件stddef.h中定义如下:

#undef NULL
#ifdef(__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif

  可以看到,NULL可能被定义为字面常量0,或者定义为无类型指针(void*)常量。这就使得在使用NULL时有些问题:

 

   在main函数中,f(NULL)调用的起始是第二个函数,因为在C++98中,字面常量0具有二义性:既可以是一个整型,也可以是一个无类型指针(void*)。如果想要调用f(char*)的话,需要对字面常量0进行强制类型转换:(void*)0 然后再调用,否则编译器总会优先把0看做一个整型常量。

nullptr_t的定义:头文件:<cstddef>

  typedef decltype(nullptr) nullptr_t;

  使用nullptr_t时必须包含头文件:<cstddef>,但是使用nullptr时则不用,因为nullptr是关键字。nullptr是有类型的,且仅可以被隐式转化为指针类型,在编写C++11代码时,使用nullptr替换NULL将使得代码更健壮。

  • nullptr:指针空值常量
  • nullptr_t:指针空值类型,也就是nullptr的类型,见上面的定义

nullptr_t注意事项:

 

 示例代码:

    char* cp = nullptr;

    //不可转换为整型,而任何类型也不能转换为nullptr_t
    //以下代码不能通过编译
    //int n1 = nullptr;
    //int n2 = reinterpret_cast<int>(nullptr);

    //nullptr与nullptr_t类型变量可以作比较
    //当使用 ==  <=  >=符号比较时返回true
    nullptr_t nptr;
    if (nptr == nullptr)
    {
        cout << "nullptr_t nptr == nullptr" << endl;
    }
    else
    {
        cout << "nullptr_t nptr != nullptr" << endl;
    }
    if (nptr < nullptr)
        cout << "nullptr_t nptr < nullptr" << endl;
    else
        cout << "nullptr_t nptr !< nullptr" << endl;

    //不能转换为整型或bool类型,以下代码不能通过编译
    //if(0 == nullptr)
    //if(nullptr)

    //不能进行算术运算,以下代码不能通过编译
    //nullptr += 1;
    //nullptr *5;

    //以下操作均可正常运行
    size_t size1 = sizeof(nullptr);
    typeid(nullptr);
    throw(nullptr);

注:如果上述代码注释部分能通过编译,可能是编译器版本不够新,在C++11中不允许上述注释代码。

   虽然nullptr_t看起来像是个指针类型,但是在把nullptr_t应用于模板中时,模板会把它作为一个普通的类型来进行推导,并不会将其视为T*指针。

template<typename T>
void g(T* t){}

template<typename T>
void h(T t){}

int main(int argc, char *argv[])
{
    g(nullptr);         //编译失败,nullptr的类型是nullptr_t,而不是指针
    g((float*) nullptr);//推导出T=float

    h(0);               //推导出T=int
    h(nullptr);         //推导出T=nullptr_t
    h((float*)nullptr); //推导出T=float*
}

 

posted @ 2020-08-13 15:06  adfas  阅读(2584)  评论(0编辑  收藏  举报