C++ 什么是nullptr?
我们现在有了具有许多新特性的C++11。一个有趣且令人困惑的(至少对我来说)是新的C++ 什么是nullptr?,c++,pointers,c++11,nullptr,C++,Pointers,C++11,Nullptr,我们现在有了具有许多新特性的C++11。一个有趣且令人困惑的(至少对我来说)是新的nullptr 嗯,不再需要讨厌的宏NULL int* x = nullptr; myclass* obj = nullptr; template <class T> class ptr { T* p_; public: ptr(T* p) : p_(p) {} template <class U> ptr(U* u) :
nullptr
嗯,不再需要讨厌的宏NULL
int* x = nullptr;
myclass* obj = nullptr;
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); }
};
不过,我还是不明白nullptr
是如何工作的。例如,他说:
C++11通过引入一个新的关键字作为一个可区分的空指针常量:nullptr来纠正这个问题。它属于类型nullptr\u t,可隐式转换,并可与任何指针类型或指向成员的指针类型进行比较。除了bool之外,它不能隐式转换,也不能与整型进行比较
它如何成为一个关键字和一个类型的实例
另外,你有没有另一个例子(除了维基百科的例子)说明
nullptr
优于旧的0
?好吧,其他语言都有作为类型实例的保留字。例如,Python:
>>> None = 5
File "<stdin>", line 1
SyntaxError: assignment to None
>>> type(None)
<type 'NoneType'>
>无=5
文件“”,第1行
SyntaxError:分配给None
>>>类型(无)
这实际上是一个相当接近的比较,因为None
通常用于未初始化的内容,但同时None==0
等比较是错误的
另一方面,在普通C中,
NULL==0
将返回真IIRC,因为NULL
只是一个返回0的宏,它总是一个无效地址(AFAIK)。它是一个关键字,因为标准会这样指定它。;-)根据最新的公开草案(n2914)
2.14.7指针文字[lex.nullptr]
pointer-literal:
nullptr
指针文本是关键字nullptr
。它是类型为std::nullptr\u t
的右值
它很有用,因为它不会隐式转换为整数值。来自:
新的C++09 nullptr关键字指定了一个用作通用空指针文本的右值常量,替换了有缺陷的弱类型文本0和臭名昭著的空宏。nullptr因此结束了30多年的尴尬、模糊和错误。以下各节介绍了nullptr功能,并展示了它如何解决NULL和0的问题
其他参考资料:
- ,带有示例代码
- 在堆栈溢出处:
- 谷歌集团:
true
和false
都是关键字,它们作为文本有一个类型(bool
)nullptr
是一个类型为std::nullptr\u t
的指针文本,它是一个PR值(不能使用和获取它的地址)
4.10
关于指针转换说明类型为std::nullptr\u t
的prvalue是一个空指针常量,整型空指针常量可以转换为std::nullptr\u t
。不允许相反方向。这允许为指针和整数重载函数,并传递nullptr
以选择指针版本。传递NULL
或0
会混淆地选择int
版本
- 将
nullptr\u t
强制转换为整数类型需要重新解释强制转换
,并且与将(void*)0
强制转换为整数类型(定义了映射实现)具有相同的语义。reinterpret\u cast
无法将nullptr\u t
转换为任何指针类型。如果可能,请依赖隐式转换或使用静态\u cast
- 该标准要求
sizeof(nullptr\t)
besizeof(void*)
当您有一个函数可以接收指向多个类型的指针时,使用NULL
调用它是不明确的。通过接受int并假设它是NULL
,现在解决这个问题的方法非常粗糙
int* x = nullptr;
myclass* obj = nullptr;
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); }
};
nullptr
不能分配给整数类型,例如int
,而只能分配给指针类型;内置指针类型,如int*ptr
,或智能指针,如std::shared\u ptr
我认为这是一个重要的区别,因为NULL
仍然可以分配给整型和指针,因为NULL
是一个扩展到0
的宏,它既可以作为int
的初始值,也可以作为指针
另外,你有没有另一个例子(除了维基百科的例子)说明nullptr
优于旧的0
对。这也是在我们的生产代码中出现的一个(简化的)真实示例。它之所以突出,是因为gcc能够在交叉编译到具有不同寄存器宽度的平台时发出警告(仍然不清楚为什么只有在从x86_64交叉编译到x86时,警告警告:从NULL转换为非指针类型“int”):
考虑以下代码(C++03):
NULL不必为0。只要使用always NULL和never 0,NULL可以是任何值。你可以编程一个冯·诺依曼微控制器,它有一个平面存储器,它的中断向量为0。如果NULL为0,并且有东西在NULL指针处写入,则微控制器崩溃。如果NULL为1024,并且在1024处有一个保留变量,则写入操作不会使其崩溃,并且您可以从程序内部检测NULL指针分配。这在个人电脑上是没有意义的,但对于太空探测器、军事或医疗设备来说,重要的是不要崩溃。假设你有一个函数(f),它被重载以获取int和char*。在C++ 11之前,如果你想用空指针调用它,并且使用null(即值0),那么你会调用int为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*)
}
为什么在C++11中使用空ptr?这是怎么一回事?为什么空值是不够的?
C++专家(我的重点用粗体加上):
void g()
{
f(nullptr); //calls f(char*)
}
void func(int n);
void func(char *s);
func( NULL ); // guess which function gets called?
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;
int *ptr = nullptr; // OK
void (C::*method_ptr)() = nullptr; // OK
char *str = NULL; // Implicit conversion from void * to char *
int i = NULL; // OK, but `i` is not pointer type
void func(int) {}
void func(int*){}
void func(bool){}
func(NULL); // Which one to call?
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
struct String
{
String(uint32_t) { /* size of string */ }
String(const char*) { /* string */ }
};
String s1( NULL );
String s2( 5 );
#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)
auto result = findRecord( /* arguments */ );
if (result == nullptr)
{
...
}
template<typename T>
void func(T *ptr)
{
...
}
func(nullptr);