现在c++ 11有了许多新特性。一个有趣而令人困惑的(至少对我来说)是新的nullptr。

不需要讨厌的宏NULL了。

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

不过,我还是不明白nullptr是如何工作的。例如,维基百科的一篇文章说:

c++ 11通过引入一个新的关键字作为区分空指针常量nullptr来纠正这一点。它的类型为nullptr_t,可隐式转换,可与任何指针类型或指针到成员类型相比较。它不能隐式转换,也不能与整型相比,bool类型除外。

它如何既是关键字又是类型的实例?

此外,你是否有另一个例子(除了维基百科的一个),其中nullptr优于好旧的0?


当前回答

它如何既是关键字又是类型的实例?

这并不奇怪。true和false都是关键字,作为字面量,它们有一个类型(bool)。Nullptr是一个std::nullptr_t类型的指针字面值,它是一个prvalue(不能使用&获取它的地址)。

4.10 about pointer conversion says that a prvalue of type std::nullptr_t is a null pointer constant, and that an integral null pointer constant can be converted to std::nullptr_t. The opposite direction is not allowed. This allows overloading a function for both pointers and integers, and passing nullptr to select the pointer version. Passing NULL or 0 would confusingly select the int version. A cast of nullptr_t to an integral type needs a reinterpret_cast, and has the same semantics as a cast of (void*)0 to an integral type (mapping implementation defined). A reinterpret_cast cannot convert nullptr_t to any pointer type. Rely on the implicit conversion if possible or use static_cast. The Standard requires that sizeof(nullptr_t) be sizeof(void*).

其他回答

根据cppreference, nullptr是一个关键字,它:

表示指针字面量。它是std::nullptr_t类型的prvalue。 存在从nullptr到空指针值的隐式转换 任何指针类型和任何指向成员类型的指针。类似的转换 存在于任何空指针常量,其中包括类型的值 std::nullptr_t以及宏NULL。

因此nullptr是一个不同类型的值std::nullptr_t,而不是int。它隐式转换为任何指针类型的空指针值。这个神奇的事情发生在您的引擎盖下,您不必担心它的实现。然而,NULL是一个宏,它是一个实现定义的空指针常量。它通常是这样定义的:

#define NULL 0

也就是一个整数。

这是一个微妙但重要的区别,可以避免歧义。

例如:

int i = NULL;     //OK
int i = nullptr;  //error
int* p = NULL;    //OK
int* p = nullptr; //OK

当你有两个像这样的函数重载:

void func(int x);   //1)
void func(int* x);  //2)

func(NULL)调用1),因为NULL是一个整数。 Func (nullptr)调用2),因为nullptr隐式转换为int*类型的指针。

另外,如果你看到这样的语句:

auto result = findRecord( /* arguments */ );

if (result == nullptr)
{
 ...
}

你不容易找到findRecord返回什么,你可以确定result必须是一个指针类型;Nullptr使其更具可读性。

在一个推断的背景下,事情的运作有点不同。如果你有一个这样的模板函数:

template<typename T>
void func(T *ptr)
{
    ...
}

你试着用nullptr调用它:

func(nullptr);

您将得到一个编译器错误,因为nullptr类型为nullptr_t。你必须显式地将nullptr转换为特定的指针类型,或者使用nullptr_t为func提供重载/专门化。


Advantages of using nulptr:

避免函数重载之间的模糊 使您能够进行模板专门化 更安全,直观和富有表现力的代码,例如if (ptr == nullptr)而不是if (ptr == 0)

从nullptr:一个类型安全和明确的空指针:

新的c++ 09 nullptr关键字指定了一个右值常量,用作通用空指针字面量,取代了有bug且弱类型的字面量0和臭名昭著的null宏。因此,Nullptr结束了30多年来的尴尬、歧义和错误。下面几节介绍nullptr功能,并展示它如何补救NULL和0的问题。

其他参考资料:

WikiBooks,带有示例代码。 Stack Overflow:在c++中,指针使用NULL还是0(零)? 模板 谷歌组:comp.lang.c++。有节制的编译器讨论

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

2.14.7指针字面量[lex.nullptr] pointer-literal: nullptr 指针字面值是关键字nullptr。它是std::nullptr_t类型的右值。

它很有用,因为它没有隐式地转换成一个整数值。

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

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

void g() 
{
  f(0); // Calls f(int).
  f(NULL); // Equals to f(0). Calls f(int).
}

这可能不是你想要的。c++ 11用nullptr解决了这个问题;现在你可以这样写:

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

它如何既是关键字又是类型的实例?

这并不奇怪。true和false都是关键字,作为字面量,它们有一个类型(bool)。Nullptr是一个std::nullptr_t类型的指针字面值,它是一个prvalue(不能使用&获取它的地址)。

4.10 about pointer conversion says that a prvalue of type std::nullptr_t is a null pointer constant, and that an integral null pointer constant can be converted to std::nullptr_t. The opposite direction is not allowed. This allows overloading a function for both pointers and integers, and passing nullptr to select the pointer version. Passing NULL or 0 would confusingly select the int version. A cast of nullptr_t to an integral type needs a reinterpret_cast, and has the same semantics as a cast of (void*)0 to an integral type (mapping implementation defined). A reinterpret_cast cannot convert nullptr_t to any pointer type. Rely on the implicit conversion if possible or use static_cast. The Standard requires that sizeof(nullptr_t) be sizeof(void*).