c++ null区别 - 什么是nullptr?




c++空指针 c++判断对象是否为空 (9)

我们现在拥有许多新功能的C ++ 11。 一个有趣和令人困惑的(至少对我来说)是新的nullptr

好吧,不再需要讨厌的宏NULL

int* x = nullptr;
myclass* obj = nullptr;

不过,我没有得到nullptr工作方式。 例如, 维基百科文章说:

C ++ 11通过引入一个新的关键字来作为一个可区分的空指针常量来纠正这个问题:nullptr。 它的类型为nullptr_t ,它可以隐式转换,并且可以与任何指针类型或成员指针类型进行比较。 除了bool以外,它不是可以隐式转换的或者可以与整数类型进行比较。

它是一个关键字和一个类型的实例?

另外,你是否还有另一个例子(维基百科之外), nullptr优于旧的0


Answers

它是一个关键字和一个类型的实例?

这并不奇怪。 truefalse都是关键字,而文字则是类型( bool )。 nullptr是一个std::nullptr_t类型的指针字面值 ,它是一个prvalue(你不能用&来取它的地址)。

  • 4.10关于指针转换说std::nullptr_t类型的prvalue是一个空指针常量,并且一个整型空指针常量可以转换为std::nullptr_t 。 相反的方向是不允许的。 这允许为指针和整数重载函数,并且传递nullptr来选择指针版本。 传递NULL0会令人困惑地选择int版本。

  • nullptr_t转换为整数类型需要reinterpret_cast ,并且具有与将(void*)0 nullptr_t转换为整型(定义的映射实现)相同的语义。 reinterpret_cast不能将nullptr_t转换为任何指针类型。 如果可能,请使用隐式转换或使用static_cast

  • 该标准要求sizeof(nullptr_t)sizeof(void*)


当你有一个函数可以接收指向多个类型的指针时,用NULL调用它是不明确的。 现在解决这个问题的方法是接受一个int并假定它是NULL ,这很糟糕。

template <class T>
class ptr {
    T* p_;
    public:
        ptr(T* p) : p_(p) {}

        template <class U>
        ptr(U* u) : p_(dynamic_cast<T*>(u)) { }

        // Without this ptr<T> p(NULL) would be ambiguous
        ptr(int null) : p_(NULL)  { assert(null == NULL); }
};

C++11你可以在nullptr_t上重载,这样ptr<T> p(42); 将是编译时错误而不是运行时assert

ptr(std::nullptr_t) : p_(nullptr)  {  }

NULL不必为0.只要您始终使用NULL且从不使用0,则NULL可以是任何值。 假设你编程一个具有平坦存储器的冯诺依曼微控制器,它的中断向量为0.如果NULL为0,并且在NULL指针处写入,则微控制器崩溃。 如果NULL表示1024并且在1024处有一个保留变量,则写入不会使其崩溃,并且可以从程序内检测NULL指针赋值。 这在PC上是毫无意义的,但对于太空探测器,军事或医疗设备来说,重要的是不要撞车。


来自nullptr:类型安全且清除空指针

新的C ++ 09 nullptr关键字指定了一个rvalue常量,它用作通用空指针字面量,代替buggy和弱类型文字0以及臭名昭着的NULL宏。 nullptr因此结束了30多年来的尴尬,模棱两可和错误。 以下部分介绍了nullptr工​​具,并展示了它如何纠正NULL和0的疾病。

其他参考:


假设您有一个函数(f)被重载以同时使用int和char *。 在C ++ 11之前,如果你想用一个空指针来调用它,并且你使用了NULL(即值为0),那么你会调用一个重载为int的指针:

void f(int);
void f(char*);

void g() 
{
  f(0); //calls f(int)
}

这可能不是你想要的。 C ++ 11用nullptr解决了这个问题; 现在您可以编写以下内容:

void g()
{
  f(nullptr); //calls f(char*)
}

为什么在C ++ 11中使用nullptr? 它是什么? 为什么NULL不够?

C ++专家Alex Allain在这里说得很完美

“...想象你有以下两个函数声明:

void func(int n); 
void func(char *s);

func( NULL ); // guess which function gets called?

虽然看起来第二个函数会被调用 - 毕竟,你传递的似乎是一个指针 - 它实际上是第一个将被调用的函数! 麻烦的是,因为NULL是0,而0是一个整数,所以func的第一个版本将被调用。 这是那种不是一直都会发生的事情,但是当它发生时,是非常令人沮丧和困惑的。 如果你不知道发生了什么的细节,它可能看起来像一个编译器错误。 看起来像编译器错误的语言功能并不是你想要的。

输入nullptr。 在C ++ 11中,nullptr是一个新的关键字,可以(并且应该)用来表示NULL指针; 换句话说,无论你在哪里写NULL,你都应该使用nullptr。 程序员 (你知道NULL是什么意思) 对你来说并不是很清楚但是它对编译器更加明确,在用作指针时,不再会看到每个地方都有特殊含义的0。


另外,你是否还有另一个例子(维基百科之外), nullptr优于旧的0?

是。 这也是我们的生产代码中出现的(简化的)真实世界的例子。 它只是因为gcc能够在交叉编译到具有不同寄存器宽度的平台时发出警告(仍然不确定为什么只有在从x86_64到x86的交叉编译时警告warning: converting to non-pointer type 'int' from NULL ) :

考虑这个代码(C ++ 03):

#include <iostream>

struct B {};

struct A
{
    operator B*() {return 0;}
    operator bool() {return true;}
};

int main()
{
    A a;
    B* pb = 0;
    typedef void* null_ptr_t;
    null_ptr_t null = 0;

    std::cout << "(a == pb): " << (a == pb) << std::endl;
    std::cout << "(a == 0): " << (a == 0) << std::endl; // no warning
    std::cout << "(a == NULL): " << (a == NULL) << std::endl; // warns sometimes
    std::cout << "(a == null): " << (a == null) << std::endl;
}

它产生这个输出:

(a == pb): 1
(a == 0): 0
(a == NULL): 0
(a == null): 1

它是一个关键字,因为标准将会这样指定它。 ;-)根据最新的公众草案(n2914)

2.14.7指针文字[lex.nullptr]

pointer-literal:
nullptr

指针文字是关键字nullptr 。 它是std::nullptr_t类型的右值。

这很有用,因为它不会隐式转换为整数值。


我将演示一个案例,其中将nullptr定义为不同类型的决定有助于防止错误。

考虑这些功能:

void foo(int);
void foo(char *);

int main()
{
    foo(NULL); // oops
}

在C ++ 98中,上面的代码调用了foo(int)函数,因为NULL被0替换,这很可能不是你想要的。

但是如果你调用foo(nullptr)它会调用正确的一个 - foo(char *)





c++ pointers c++11 nullptr