C++ nullptr 究竟是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1282295/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What exactly is nullptr?
提问by AraK
We now have C++11 with many new features. An interesting and confusing one (at least for me) is the new nullptr
.
我们现在拥有具有许多新功能的 C++11。一个有趣且令人困惑的(至少对我而言)是新的nullptr
.
Well, no need anymore for the nasty macro NULL
.
好吧,不再需要讨厌的宏了NULL
。
int* x = nullptr;
myclass* obj = nullptr;
Still, I am not getting how nullptr
works. For example, Wikipedia articlesays:
尽管如此,我还是不明白是如何nullptr
工作的。例如,维基百科文章说:
C++11 corrects this by introducing a new keywordto serve as a distinguished null pointer constant: nullptr. It is of type nullptr_t, which is implicitly convertible and comparable to any pointer type or pointer-to-member type. It is not implicitly convertible or comparable to integral types, except for bool.
C++11 通过引入一个新的关键字作为一个特殊的空指针常量来纠正这个问题:nullptr。它的类型为 nullptr_t,它可以隐式转换并与任何指针类型或指向成员的指针类型相比较。除了 bool 之外,它不能隐式转换或与整型比较。
How is it a keyword and an instance of a type?
关键字和类型的实例如何?
Also, do you have another example (beside the Wikipedia one) where nullptr
is superior to good old 0
?
另外,你还有另一个例子(在维基百科旁边)nullptr
优于 good old0
吗?
采纳答案by Johannes Schaub - litb
How is it a keyword and an instance of a type?
关键字和类型的实例如何?
This isn't surprising. Both true
and false
are keywords and as literals they have a type ( bool
). nullptr
is a pointer literalof type std::nullptr_t
, and it's a prvalue (you cannot take the address of it using &
).
这并不奇怪。这两个true
和false
是关键字和文字他们有一个类型(bool
)。nullptr
是一个类型为 的指针文字std::nullptr_t
,它是一个纯右值(你不能使用它获取它的地址&
)。
4.10
about pointer conversion says that a prvalue of typestd::nullptr_t
is a null pointer constant, and that an integral null pointer constant can be converted tostd::nullptr_t
. The opposite direction is not allowed. This allows overloading a function for both pointers and integers, and passingnullptr
to select the pointer version. PassingNULL
or0
would confusingly select theint
version.A cast of
nullptr_t
to an integral type needs areinterpret_cast
, and has the same semantics as a cast of(void*)0
to an integral type (mapping implementation defined). Areinterpret_cast
cannot convertnullptr_t
to any pointer type. Rely on the implicit conversion if possible or usestatic_cast
.The Standard requires that
sizeof(nullptr_t)
besizeof(void*)
.
4.10
关于指针转换说类型的纯右值std::nullptr_t
是空指针常量,并且整型空指针常量可以转换为std::nullptr_t
. 不允许相反方向。这允许为指针和整数重载函数,并传递nullptr
以选择指针版本。通过NULL
或0
会混淆地选择int
版本。的铸造
nullptr_t
为整型需要reinterpret_cast
,并且具有相同的语义的铸造(void*)0
为整型(映射实现定义)。Areinterpret_cast
不能转换nullptr_t
为任何指针类型。如果可能,依靠隐式转换或使用static_cast
.该标准要求
sizeof(nullptr_t)
是sizeof(void*)
.
回答by nik
From nullptr: A Type-safe and Clear-Cut Null Pointer:
The new C++09 nullptr keyword designates an rvalue constant that serves as a universal null pointer literal, replacing the buggy and weakly-typed literal 0 and the infamous NULL macro. nullptr thus puts an end to more than 30 years of embarrassment, ambiguity, and bugs. The following sections present the nullptr facility and show how it can remedy the ailments of NULL and 0.
新的 C++09 nullptr 关键字指定了一个右值常量,用作通用空指针字面量,取代了错误和弱类型字面量 0 以及臭名昭著的 NULL 宏。因此,nullptr 结束了 30 多年的尴尬、模棱两可和错误。以下部分介绍了 nullptr 工具,并展示了它如何解决 NULL 和 0 的问题。
Other references:
其他参考:
- WikiBooks, with sample code.
- Here at Stack Overflow: Do you use NULL or 0 (zero) for pointers in C++?
template
- Google group: comp.lang.c++.moderated - compiler discussion
- WikiBooks,带有示例代码。
- 在 Stack Overflow:C++ 中的指针使用 NULL 还是 0(零)?
template
- Google 群:comp.lang.c++.moderated - 编译器讨论
回答by Gabriel Staples
Why nullptr in C++11? What is it? Why is NULL not sufficient?
为什么在 C++11 中使用 nullptr?它是什么?为什么 NULL 不够?
C++ expert Alex Allain says it perfectly here(my emphasis added in bold):
C++ 专家亚历克斯·阿兰 (Alex Allin) 在这里说得很好(我的重点用粗体表示):
...imagine you have the following two function declarations:
void func(int n); void func(char *s); func( NULL ); // guess which function gets called?
Although it looks like the second function will be called--you are, after all, passing in what seems to be a pointer--it's really the first function that will be called! The trouble is that because NULL is 0, and 0 is an integer, the first version of func will be called instead.This is the kind of thing that, yes, doesn't happen all the time, but when it does happen, is extremely frustrating and confusing. If you didn't know the details of what is going on, it might well look like a compiler bug. A language feature that looks like a compiler bug is, well, not something you want.
Enter nullptr. In C++11, nullptr is a new keyword that can (and should!) be used to represent NULL pointers;in other words, wherever you were writing NULL before, you should use nullptr instead. It's no more clear to you, the programmer, (everyone knows what NULL means), but it's more explicit to the compiler, which will no longer see 0s everywhere being used to have special meaning when used as a pointer.
...假设您有以下两个函数声明:
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 具有特殊含义。
Allain ends his article with:
阿兰以这样的方式结束他的文章:
Regardless of all this--the rule of thumb for C++11 is simply to start using
nullptr
whenever you would have otherwise usedNULL
in the past.
不管这一切——C++11 的经验法则是
nullptr
只要你NULL
过去会使用,就开始使用。
(My words):
(我的话):
Lastly, don't forget that nullptr
is an object--a class. It can be used anywhere NULL
was used before, but if you need its type for some reason, it's type can be extracted with decltype(nullptr)
, or directly described as std::nullptr_t
, which is simply a typedef
of decltype(nullptr)
.
最后,不要忘记它nullptr
是一个对象——一个类。它可以在任何地方使用NULL
前使用,但是如果你需要它的类型出于某种原因,它的类型可以被提取decltype(nullptr)
,或直接描述为std::nullptr_t
,这是一个简单的typedef
的decltype(nullptr)
。
References:
参考:
回答by Motti
When you have a function that can receive pointers to more than one type, calling it with NULL
is ambiguous. The way this is worked around now is very hacky by accepting an int and assuming it's NULL
.
当您有一个可以接收指向多个类型的指针的函数时,用 with 调用它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); }
};
In C++11
you would be able to overload on nullptr_t
so that ptr<T> p(42);
would be a compile-time error rather than a run-time assert
.
在C++11
你将能够重载,nullptr_t
所以这ptr<T> p(42);
将是一个编译时错误而不是一个运行时错误assert
。
ptr(std::nullptr_t) : p_(nullptr) { }
回答by user633658
nullptr
can't be assigned to an integral type such as an int
but only a pointer type; either a built-in pointer type such as int *ptr
or a smart pointer such as std::shared_ptr<T>
nullptr
不能分配给一个整数类型,例如 anint
而只能分配一个指针类型;内置指针类型,例如int *ptr
或智能指针,例如std::shared_ptr<T>
I believe this is an important distinction because NULL
can still be assigned to both an integral type and a pointer as NULL
is a macro expanded to 0
which can serve as both an initial value for an int
as well as a pointer.
我相信这是一个重要的区别,因为NULL
仍然可以分配给整数类型和指针,就像NULL
扩展到的宏一样,0
它既可以用作 an 的初始值,也可以用作int
指针。
回答by Gabriel Schreiber
Also, do you have another example (beside the Wikipedia one) where
nullptr
is superior to good old 0?
另外,您是否还有另一个示例(在维基百科旁边)
nullptr
优于 Good old 0 的示例?
Yes. It's also a (simplified) real-world example that occurred in our production code. It only stood out because gcc was able to issue a warning when crosscompiling to a platform with different register width (still not sure exactly why only when crosscompiling from x86_64 to x86, warns warning: converting to non-pointer type 'int' from NULL
):
是的。这也是我们生产代码中发生的(简化的)现实世界示例。它之所以突出是因为 gcc 在交叉编译到具有不同寄存器宽度的平台时能够发出警告(仍然不确定为什么只有在从 x86_64 交叉编译到 x86 时,警告warning: converting to non-pointer type 'int' from NULL
):
Consider this code (C++03):
考虑这个代码(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;
}
It yields this output:
它产生这个输出:
(a == pb): 1
(a == 0): 0
(a == NULL): 0
(a == null): 1
回答by Mark Rushakoff
Well, other languages have reserved words that are instances of types. Python, for instance:
好吧,其他语言都有作为类型实例的保留字。以 Python 为例:
>>> None = 5
File "<stdin>", line 1
SyntaxError: assignment to None
>>> type(None)
<type 'NoneType'>
This is actually a fairly close comparison because None
is typically used for something that hasn't been intialized, but at the same time comparisons such as None == 0
are false.
这实际上是一个相当接近的比较,因为None
通常用于尚未初始化的东西,但同时比较诸如None == 0
false。
On the other hand, in plain C, NULL == 0
would return true IIRC because NULL
is just a macro returning 0, which is always an invalid address (AFAIK).
另一方面,在普通 C 中, NULL == 0
将返回真正的 IIRC,因为NULL
它只是一个返回 0 的宏,这始终是一个无效地址(AFAIK)。
回答by KTC
It is a keyword because the standard will specify it as such. ;-) According to the latest public draft (n2914)
它是一个关键字,因为标准将这样指定它。;-) 根据最新的公开草案 (n2914)
2.14.7 Pointer literals [lex.nullptr]
pointer-literal: nullptr
The pointer literal is the keyword
nullptr
. It is an rvalue of typestd::nullptr_t
.
2.14.7 指针字面量 [lex.nullptr]
pointer-literal: nullptr
指针文字是关键字
nullptr
。它是一个类型的右值std::nullptr_t
。
It's useful because it does not implicitly convert to an integral value.
它很有用,因为它不会隐式转换为整数值。
回答by Amit G.
Let's say that you have a function (f) which is overloaded to take both int and char*. Before C++ 11, If you wanted to call it with a null pointer, and you used NULL (i.e. the value 0), then you would call the one overloaded for int:
假设您有一个函数 (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).
}
This is probably not what you wanted. C++11 solves this with nullptr; Now you can write the following:
这可能不是您想要的。C++11 用 nullptr 解决了这个问题;现在您可以编写以下内容:
void g()
{
f(nullptr); //calls f(char*)
}
回答by Vishal Chovatiya
Let me first give you an implementation of unsophisticated nullptr_t
先给大家介绍一个不成熟的实现 nullptr_t
struct nullptr_t
{
void operator&() const = delete; // Can't take address of nullptr
template<class T>
inline operator T*() const { return 0; }
template<class C, class T>
inline operator T C::*() const { return 0; }
};
nullptr_t nullptr;
nullptr
is a subtle example of Return Type Resolveridiom to automatically deduce a null pointer of the correct type depending upon the type of the instance it is assigning to.
nullptr
是返回类型解析器习语的一个微妙示例,它根据分配给的实例的类型自动推导出正确类型的空指针。
int *ptr = nullptr; // OK
void (C::*method_ptr)() = nullptr; // OK
- As you can above, when
nullptr
is being assigned to an integer pointer, aint
type instantiation of the templatized conversion function is created. And same goes for method pointers too. - This way by leveraging template functionality, we are actually creating the appropriate type of null pointer every time we do, a new type assignment.
- As
nullptr
is an integer literal with value zero, you can not able to use its address which we accomplished by deleting & operator.
- 如上所述,当
nullptr
被分配给整数指针时,int
会创建模板化转换函数的类型实例化。方法指针也是如此。 - 通过这种方式,通过利用模板功能,我们实际上每次都创建了适当类型的空指针,一个新的类型分配。
- 由于
nullptr
是值为 0 的整数文字,您不能使用我们通过删除 & 运算符完成的地址。
Why do we need nullptr
in the first place?
为什么我们nullptr
首先需要?
- You see traditional
NULL
has some issue with it as below:
- 您会看到传统
NULL
有一些问题,如下所示:
1???Implicit conversion
1???隐式转换
char *str = NULL; // Implicit conversion from void * to char *
int i = NULL; // OK, but `i` is not pointer type
2???Function calling ambiguity
2???函数调用歧义
void func(int) {}
void func(int*){}
void func(bool){}
func(NULL); // Which one to call?
- Compilation produces the following error:
- 编译产生以下错误:
error: call to 'func' is ambiguous
func(NULL);
^~~~
note: candidate function void func(bool){}
^
note: candidate function void func(int*){}
^
note: candidate function void func(int){}
^
1 error generated.
compiler exit status 1
3???Constructor overload
3???构造函数重载
struct String
{
String(uint32_t) { /* size of string */ }
String(const char*) { /* string */ }
};
String s1( NULL );
String s2( 5 );
- In such cases, you need explicit cast (i.e.,?
String s((char*)0))
.
- 在这种情况下,您需要显式转换(即?
String s((char*)0))
。