什么是nullptr?

Ara*_*raK 546 c++ pointers nullptr c++11

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

嗯,不再需要令人讨厌的宏了NULL.

int* x = nullptr;
myclass* obj = nullptr;
Run Code Online (Sandbox Code Playgroud)

尽管如此,我还没有得到如何nullptr运作.例如,维基百科的文章说:

C++ 11通过引入一个new 关键字作为一个区分空指针常量来解决这个问题:nullptr.它的类型为nullptr_t,它是可隐式转换的,可与任何指针类型或指向成员类型的类型相媲美.除了bool之外,它不可隐式转换或与整数类型相比.

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

另外,你有另一个例子(在维基百科旁边)哪里nullptr优于好老0

Joh*_*itb 384

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

这并不奇怪.这两个truefalse是关键字和文字他们有一个类型(bool).nullptr是一个类型的指针文字std::nullptr_t,它是一个prvalue(你不能使用它的地址&).

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

  • 的铸造nullptr_t为整型需要reinterpret_cast,并且具有相同的语义的铸造(void*)0为整型(映射实现定义).A reinterpret_cast无法转换nullptr_t为任何指针类型.如果可能,请依靠隐式转换或使用static_cast.

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

  • 请注意,"NULL"甚至不能保证为"0".它可以是`0L`,在这种情况下调用`void f(int); void f(char*);`将是不明确的.`nullptr`总是支持指针版本,永远不会调用`int`.另请注意,`nullptr`*是*可转换为`bool`(草案说是在`4.12`). (81认同)
  • @Steve,不会调用`int`版本.但是`f(0L)`是不明确的,因为`long - > int`以及`long - > void*`都是同样昂贵的.因此,如果编译器上的NULL为"0L",那么在给定这两个函数的情况下调用`f(NULL)`将是不明确的.当然,`nullptr`不是这样. (27认同)
  • @SvenS不能在C ++中定义为`(void *)0`。但是它可以被定义为任意的空指针常量,任何值为0和`nullptr`的整数常量都可以满足。因此,绝对不是*会*,而是*可以*。(你忘了给我ping一下。) (2认同)

nik*_*nik 57

来自nullptr:一个Type-safe和Clear-Cut Null指针:

新的C++ 09 nullptr关键字指定一个rvalue常量,用作通用空指针文字,替换错误和弱类型的文字0和臭名昭着的NULL宏.因此,nullptr结束了超过30年的尴尬,模棱两可和错误.以下部分介绍了nullptr工​​具,并展示了如何解决NULL和0的问题.

其他参考:

  • C++ 09?在2011年8月之前它不是被称为C++ 0x吗? (16认同)
  • @anthropomorphic那就是它的目的.C++ 0x在它仍在进行中时使用,因为不知道它是在2008年还是2009年完成.注意它实际上变成了C++ 0B,意思是C++ 11.见http://www.stroustrup.com/C++11FAQ.html (2认同)

Mot*_*tti 36

当你有一个可以接收指向多个类型的指针的函数时,调用它NULL是不明确的.现在解决这个问题的方法是接受一个int并假设它是非常hacky 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); }
};
Run Code Online (Sandbox Code Playgroud)

C++11你可以重载,nullptr_tptr<T> p(42);将是一个编译时错误而不是运行时assert.

ptr(std::nullptr_t) : p_(nullptr)  {  }
Run Code Online (Sandbox Code Playgroud)


Gab*_*les 30

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

C++专家Alex Allain在这里完美地说:

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

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

func( NULL ); // guess which function gets called?
Run Code Online (Sandbox Code Playgroud)

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

输入nullptr.在C++ 11中,nullptr是一个新的关键字,可以(并且应该!)用于表示NULL指针; 换句话说,无论你以前写过NULL,都应该使用nullptr.对于程序员来说,你不再清楚(每个人都知道NULL意味着什么),但它对编译器来说更加明确,当用作指针时,编译器将不会再看到任何地方被用来具有特殊含义的0."

  • 我必须说你的答案被低估了,通过你的例子很容易理解。 (6认同)

use*_*658 9

nullptr不能分配给int诸如int之类但只能分配类型int *ptr; 要么是内置的指针类型,std::shared_ptr<T>要么是智能指针等NULL

我相信这是一个重要的区别,因为NULL仍然可以分配到一个0int作为nullptr是一个宏扩展到了int它可以作为一个既初始值int *ptr以及一个std::shared_ptr<T>.


Mar*_*off 5

好吧,其他语言也保留了作为类型实例的保留字。例如,Python:

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

实际上,这是一个相当接近的比较,因为None通常将其用于尚未初始化的事物,但与此同时,诸如None == 0false之类的比较也是如此。

另一方面,在纯C中, NULL == 0将返回true IIRC,因为NULL只是一个返回0的宏,它始终是无效地址(AFAIK)。

  • NULL是一个扩展为零的宏,将常量零强制转换为指针会生成一个空指针。空指针不必一定为零(但通常是),零并不总是无效的地址,并且将非常量零强制转换为指针不必一定为空,而将空指针强制转换为整数不必为零。我希望我一切都好,不要忘记任何事情。参考:http://c-faq.com/null/null2.html (4认同)

Gab*_*ber 5

另外,您是否还有另一个示例(除了Wikipedia之外)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;
}
Run Code Online (Sandbox Code Playgroud)

它产生以下输出:

(a == pb): 1
(a == 0): 0
(a == NULL): 0
(a == null): 1
Run Code Online (Sandbox Code Playgroud)


小智 5

让我首先给你一个简单的实现nullptr_t

\n
struct nullptr_t \n{\n    void operator&() const = delete;  // Can\'t take address of nullptr\n\n    template<class T>\n    inline operator T*() const { return 0; }\n\n    template<class C, class T>\n    inline operator T C::*() const { return 0; }\n};\n\nnullptr_t nullptr;\n
Run Code Online (Sandbox Code Playgroud)\n

nullptr是返回类型解析器习惯用法的一个微妙示例,它根据分配给它的实例的类型自动推断出正确类型的空指针。

\n
int *ptr = nullptr;                // OK\nvoid (C::*method_ptr)() = nullptr; // OK\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  • 如上所述,当nullptr将 分配给整数指针时,int将创建模板化转换函数的类型实例化。方法指针也是如此。
  • \n
  • 这样,通过利用模板功能,我们实际上每次都会创建适当类型的空指针,即新的类型分配。
  • \n
  • 由于nullptr是值为零的整数文字,因此您无法使用我们通过删除 & 运算符来完成的地址。
  • \n
\n

nullptr首先我们为什么需要?

\n
    \n
  • 您会看到传统的NULL有一些问题,如下所示:
  • \n
\n

1\xef\xb8\x8f\xe2\x83\xa3\xc2\xa0隐式转换

\n
char *str = NULL; // Implicit conversion from void * to char *\nint i = NULL;     // OK, but `i` is not pointer type\n
Run Code Online (Sandbox Code Playgroud)\n

2\xef\xb8\x8f\xe2\x83\xa3\xc2\xa0函数调用歧义

\n
void func(int) {}\nvoid func(int*){}\nvoid func(bool){}\n\nfunc(NULL);     // Which one to call?\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  • 编译产生以下错误:
  • \n
\n
error: call to \'func\' is ambiguous\n    func(NULL);\n    ^~~~\nnote: candidate function void func(bool){}\n                              ^\nnote: candidate function void func(int*){}\n                              ^\nnote: candidate function void func(int){}\n                              ^\n1 error generated.\ncompiler exit status 1\n
Run Code Online (Sandbox Code Playgroud)\n

3\xef\xb8\x8f\xe2\x83\xa3\xc2\xa0构造函数重载

\n
struct String\n{\n    String(uint32_t)    {   /* size of string */    }\n    String(const char*) {       /* string */        }\n};\n\nString s1( NULL );\nString s2( 5 );\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  • 在这种情况下,您需要显式转换(即\xc2\xa0 String s((char*)0)).
  • \n
\n