[转]为什么要引入nullptr?

来源:https://cloud.tencent.com/developer/ask/69685

C++11介绍nullptr,它被称为Null指针常数及其提高类型安全性解决不明确的情况与现有实现相关的空指针常量不同NUL。能够理解nullptr我们首先要明白什么是NULL与此相关的问题是什么。

何谓NULL一点儿没错

Pre C++11NULL用于表示没有值的指针或不指向任何有效内容的指针。与流行的观念相反NULL不是C++中的关键字。它是标准库标头中定义的标识符。总之,你不能用NULL而不包括一些标准库头

int main()
{ 
    int *ptr = NULL;
    return 0;
}

产出:

prog.cpp: In function 'int main()':
prog.cpp:3:16: error: 'NULL' was not declared in this scope

C++标准将NULL定义为在某些标准库头文件中定义的实现宏。NULL的起源来自C,C++继承了它。C标准将NULL定义为0或(无效)*)0。但是在C++中有一个微妙的区别。

C++不能接受这个规范。与C不同,C++是一种强类型语言。void*对于任何类型,而C++强制执行显式强制转换),这使得C标准指定的NULL定义在许多C++表达式中毫无用处,例如:

std::string * str = NULL;         //Case 1
void (A::*ptrFunc) () = &A::doSomething;
if (ptrFunc == NULL) {}           //Case 2

如果NULL被定义为(无效)*)0。以上两个表达式都不能工作。

  • 案例1:不编译,因为需要自动转换。void *std::string...
  • 案例2:将不会编译,因为void *指向成员函数的指针是必需的。

因此,与C、C++标准不同,C++标准授权将NULL定义为数字文字0或0L。

那么,当我们有一个空指针常量时,还需要什么呢?NULL已经开始了?

尽管C++标准委员会提出了一个适用于C++的零定义,但这个定义也有其自身的一些问题。NULL对于几乎所有的场景都足够好,但不是全部。对于某些罕见的情况,它给出了令人惊讶和错误的结果。

#include<iostream>
void doSomething(int)
{
    std::cout<<"In Int version";
}
void doSomething(char *)
{
   std::cout<<"In char* version";
}

int main()
{
    doSomething(NULL);
    return 0;
}

产出:

In Int version

很明显,其意图似乎是要调用使用char的版本。*作为参数,但当输出显示作为int版本的函数被调用时。这是因为NULL是一个数字文字。

此外,由于实现定义了NULL可以是0还是0L,因此函数重载解析可能会出现很多混乱。

样本计划:

#include <cstddef>

void doSomething(int);
void doSomething(char *);

int main()
{
  doSomething(static_cast <char *>(0));    // Case 1
  doSomething(0);                          // Case 2
  doSomething(NULL)                        // Case 3
}

分析上面的片段:

  • 案例1:打电话doSomething(char *)如预期
  • 案例2:打电话doSomething(int)但也许char*需要版本是因为0也是空指针。
  • 案例3:如果NULL定义为0,,, 打电话doSomething(int)也许当doSomething(char *)可能会导致运行时出现逻辑错误。 但是,如果NULL定义为0L,,, 调用不明确,导致编译错误。

因此,根据实现的不同,相同的代码可以提供不同的结果,这显然是不可取的。当然,C++标准委员会希望纠正这一点,这是nullptr的主要动机。


所以什么是nullptr以及如何避免NULL?

C++11引入了一个新的关键字nullptr作为空指针常量。与NULL不同,它的行为不是定义的实现。它不是宏,但它有自己的类型。nullptr有std::nullptr_t...。C++11适当地定义了nullptr的属性,以避免NULL的缺点。概括一下它的性质:

财产1:它有它自己的类型std::nullptr_t

财产2:它是隐式可转换的,可与任何指针类型或指针到成员类型相比较,但是

财产3:它不是隐式可转换的,也不是可与积分类型相比较的,除非bool...

考虑以下示例:

#include<iostream>
void doSomething(int)
{
    std::cout<<"In Int version";
}
void doSomething(char *)
{
   std::cout<<"In char* version";
}

int main()
{
    char *pc = nullptr;      // Case 1
    int i = nullptr;         // Case 2
    bool flag = nullptr;     // Case 3

    doSomething(nullptr);    // Case 4
    return 0;
}

在上面的节目中,

  • 案例1:OK-财产2
  • 案例2:不确定-财产3
  • 案例3:OK-财产3
  • 案例4:没有混淆-呼叫char *版本,属性2和3

因此,nullptr的引入避免了好的旧空的所有问题。

你应该如何和在哪里使用nullptr?

C++11的经验法则是简单地开始使用nullptr当你以前使用空的时候。

posted @ 2019-12-12 22:58  castchen  阅读(433)  评论(0编辑  收藏  举报