nullptr是什么?
nullptr是什么?
我们现在有了很多新功能的C++11版本。一种有趣而令人困惑的新特性(至少对我而言)是新的nullptr
。
现在不需要那个讨厌的NULL
宏了。
int* x = nullptr; myclass* obj = nullptr;
尽管如此,我还是不明白nullptr
是如何工作的。例如,维基百科上的文章说:
C++11通过引入一个新的关键字来作为突出的空指针常量:nullptr。它是<强>nullptr_t类型,可以隐式地转换和比较任何指针类型或成员指针类型。除了bool之外,它不可隐式转换或比较整数类型。
它是如何成为关键字和一个类型的实例?
此外,你有另一个例子(除了维基百科上的)证明nullptr
优于旧的0
吗?
为什么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函数。虽然这种情况不是经常发生,但当发生时,是非常令人沮丧和困惑的。如果你不知道正在发生的细节,它可能看起来像编译器的bug。一个看起来像编译器bug的语言特性,显然不是你想要的。
这便引入了nullptr。在C++11中,nullptr是一个新的关键字,应该(而且应该!)用于代替NULL指针;换句话说,在以前使用NULL的任何地方,你现在应该使用nullptr。 它对你这个程序员来说并不更清楚(每个人都知道NULL的含义),但它对编译器更明确,编译器不再看到0被用于具有特殊含义的指针。
Allain在他的文章中写道:
不管怎样——对于C++11的一般规则是,只要以前会使用
NULL
,现在就应该开始使用nullptr
。
(以下为我的话):
最后,不要忘记nullptr
是一个对象——一个类。它可以用于以前使用NULL
的任何地方,但如果你因某种原因需要它的类型,它的类型可以使用decltype(nullptr)
来提取,或者直接用std::nullptr_t
描述,它只是decltype(nullptr)
的typedef
,如下所示:
头文件
中定义:
参见:
namespace std { typedef decltype(nullptr) nullptr_t; // (since C++11) // OR (same thing, but using the C++ keyword `using` instead of the C and C++ // keyword `typedef`): using nullptr_t = decltype(nullptr); // (since C++11) } // namespace std
参考资料:
- Cprogramming.com: Better types in C++11 - nullptr, enum classes (strongly typed enumerations) and cstdint
- https://en.cppreference.com/w/cpp/language/decltype
- https://en.cppreference.com/w/cpp/types/nullptr_t
- https://en.cppreference.com/w/cpp/header/cstddef
- https://en.cppreference.com/w/cpp/keyword/using
- https://en.cppreference.com/w/cpp/keyword/typedef
它是如何成为关键字和类型的实例的呢?
这并不令人惊讶。 true
和 false
都是关键字,并且作为文字它们具有类型(bool
)。 nullptr
是类型为 std::nullptr_t
的指针文字,它是 prvalue 类型(无法使用 &
采取它的地址)。
-
关于指针转换的
4.10
规则说明,std::nullptr_t
类型的 prvalue 是空指针常量,并且可以将整数空指针常量转换为std::nullptr_t
。反向转换是不允许的。这允许为指针和整数重载函数,并通过传递nullptr
选择指针版本。传递NULL
或0
会令人困惑地选择int
版本。 -
将
nullptr_t
强制转换为整数类型需要使用reinterpret_cast
,并且具有与将(void*)0
转换为整数类型的强制转换相同的语义(映射实现定义)。reinterpret_cast
无法将nullptr_t
转换为任何指针类型。如果可能的话,依靠隐式转换或使用static_cast
。 -
标准要求
sizeof(nullptr_t)
等于sizeof(void*)
。