当前位置: 代码迷 >> 综合 >> C++11之指针空值--nullptr
  详细解决方案

C++11之指针空值--nullptr

热度:78   发布时间:2023-10-11 21:46:23.0

引入nullptr的意义

在C++程序开发中,为了提高代码的健壮性,一般会在定义指针的同时会完成初始化操作(避免出现野指针),在指针指向尚未明确的情况下,都会给指针初始化为空指针。在C++98/03标准中,将一个指针初始化为空指针的方式有两种:

char *ptr = 0;
char *ptr = NULL;

在底层源码中 NULL 这个宏是这样定义的:

#ifndef NULL#ifdef __cplusplus#define NULL 0#else#define NULL ((void *)0)#endif
#endif

可以看出,NULL可能被定义为字面常量0,或者是定义为无类型指针(void*)0。原因:由于 C++中,void类型无法隐式转换为其他类型的指针,此时使用0代替((void)0),用于解决空指针的问题。这个0(0x00000000)表示的就是虚拟地址空间中的 0 地址,这块地址是只读的。但是无论采用什么样的定义方式,我们在使用空值的指针时,都不可避免地会遇到一些麻烦;

如下代码:

 #include <iostream>using namespace std;void fun(char *c){
    cout << "void func(char *c)" << endl;}void fun(int i)
{
    cout << "void func(int i)" << endl;
}
int main()
{
    // 想要调用重载函数 void func(char *p)func(NULL);  //注:如果使用gcc编译,NULL转化为内部标识 __null,该语句会编译失败 // 想要调用重载函数 void func(int i)func(0);    func((char*)0);return 0;
}

输出:

void func(int i)
void func(int i)
void func(char *c)

虽然调用 func(NULL); 最终链接到的还是 void func(int p) 和预期是不一样的;原因:C++ 中将 NULL 定义为字面常量 0,并不能保证在所有场景下都能很好的工作,比如,函数重载时,NULL 和 0 无法区分;

在C++11新标准这,出于兼容性的考虑,字面常量0的二义性并没有被消除;但是标准为二义性给出了新的答案,就是使用nullptr;在C++11 新标准中,nullptr是一个所谓“指针空值类型”的常量;指针空值类型被命名为nullptr_t。

可以在支持nullptr的头文件(csddef)中找到如下定义:

typedef decltype(nullptr) nullptr_t;

使用nullptr_t的时候必须#include(#include有些头文件也会间接#include,比如),而nullptr则不用。

大概就是由于nullptr是关键字,而nullptr_t是通过推导而来的缘故。

对上述程序进行修改:

 #include <iostream>using namespace std;void fun(char *c){
    cout << "void func(char *c)" << endl;}void fun(int i)
{
    cout << "void func(int i)" << endl;
}int main()
{
    //调用重载函数 void func(char *p)func(nullptr);   //调用重载函数 void func(int i)func(0);    return 0;
}

结果:

void func(char *c)
void func(int i)

可以看出,nullptr 无法隐式转换为整形,但是可以隐式匹配指针类型。在 C++11 标准下,相比 NULL 和 0,使用 nullptr 初始化空指针可以令我们编写的程序更加健壮。

nullptr和nullptr_t

C++11标准不仅定义了指针空值常量nullptr,也定义了其指针空值类型nullptr_t,也就表示了指针空值类型并非仅有nullptr一个实例。通常情况下,也可以通过nullptr_t来声明一个指针空值类型的变量(即使看起来用途不大)。

除去nullptr及nullptr_t以外,C++中还存在各种内置类型。C++11标准严格规定了数据间的关系。常见的规则简单地列在了下面:

  1. 所有定义为nullptr_t类型的数据都是等价的,行为也是完全一致。
  2. nullptr_t类型数据可以隐式转换成任意一个指针类型。
  3. nullptr_t类型数据不能转换为非指针类型,即使使用reinterpret_cast()的方式也是不可以的。
  4. nullptr_t类型数据不适用于算术运算表达式。
  5. nullptr_t类型数据可以用于关系运算表达式,但仅能与nullptr_t类型数据或者指针类型数据进行比较,当且仅当关系运算符为==、<=、>=等时返回true。