c++ - 空指针 - nullptr null区别




什么是nullptr? (7)

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

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

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

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

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

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

另外,你是否还有另一个例子(维基百科之外), nullptr优于旧的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

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

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


nullptr不能被分配给一个integral type比如int,但只能是一个类型pointer ; 内置指针类型(如int *ptr或智能指针(如std::shared_ptr<T>

我认为这是一个重要的区别,因为NULL仍然可以分配给integral typepointer因为NULL是一个扩展为0的宏,它既可以作为int的初始值,也可以作为pointer


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

2.14.7指针文字[lex.nullptr]

pointer-literal:
nullptr

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

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


当你有一个函数可以接收指向多个类型的指针时,用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)  {  }

那么,其他语言已经保留了类型实例的单词。 Python,例如:

>>> None = 5
  File "<stdin>", line 1
SyntaxError: assignment to None
>>> type(None)
<type 'NoneType'>

这实际上是一个非常接近的比较,因为None通常用于没有初始化的东西,但同时比较如None == 0是错误的。

另一方面,在普通的C中, NULL == 0将返回真正的IIRC,因为NULL只是一个返回0的宏,这总是一个无效地址(AFAIK)。





nullptr