nullptr

指针空值类型 nullptr

在 C++ 程序开发中,为了提高程序的健壮性,一般会在定义指针的同时完成初始化操作,或者在指针的指向尚未明确的情况下,
都会给指针初始化为 NULL,避免产生野指针(没有明确指向的指针,操作这种指针可能导致程序发生异常)。
C++98/03 标准中,将一个指针初始化为空指针的方式有两种:

1
2
char *ptr = 0;
char *ptr = NULL;

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

1
2
3
4
5
6
7
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

如果源码是 C++ 程序 NULL 就是 0;如果是 C 程序 NULL 表示 (void*)0。为什么要这样做?
C++ 中 void* 类型无法隐式转换为其他类型的指针,此时使用 0 代替 ((void *)0),用于解决空指针的问题。
这个 0(0x0000 0000) 表示的就是虚拟地址空间中的 0 地址,这块地址是只读的。

C++ 中将 NULL 定义为字面常量 0,并不能保证在所有场景下都能很好的工作。
比如,函数重载时,NULL0 无法区分:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;

void func(char *p)
{
cout << "void func(char *p)" << endl;
}

void func(int p)
{
cout << "void func(int p)" << endl;
}

int main(int argc, char* argv[])
{
// func(NULL); // 报错
func(199); // 调用重载函数 void func(int p)

return 0;
}

出于兼容性的考虑,C++11 标准并没有对 NULL 的宏定义做任何修改,而是引入了一个新的关键字 nullptr
C++ 中指针必须有明确的类型定义,nullptr 专用于初始化空类型指针,不同类型的指针变量都可以使用 nullptr 来初始化:

1
2
3
int*    ptr1 = nullptr;
char* ptr2 = nullptr;
double* ptr3 = nullptr;

编译器分别将 nullptr 隐式转换成 int*、char* 以及 double* 指针类型。
使用 nullptr 可以解决上边提到的函数重载问题:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
using namespace std;

void func(char *p)
{
cout << "void func(char *p)" << endl;
}

void func(int p)
{
cout << "void func(int p)" << endl;
}

int main(int argc, char* argv[])
{
func(nullptr); // 调用重载函数 void func(char *p)
func(199); // 调用重载函数 void func(int p)

return 0;
}

总结:nullptr 无法隐式转换为整形,但是可以隐式匹配指针类型。
在 C++11 标准下,相比 NULL0,使用 nullptr 初始化空指针可以令编写的程序更加健壮。
扩展:C++ nullptr 的实现

参考资料

https://subingwen.cn/cpp/nullptr/


nullptr
https://lcf163.github.io/2021/09/12/nullptr/
作者
乘风的小站
发布于
2021年9月12日
许可协议