文章目录
【 0. 问题背景 】 0.1 野指针和悬空指针 0.2 传统空指针 NULL 0.3 传统空指针的局限性
【 1. 基本用法 】 【 2. nullptr 的应用 】 2.1 nullptr 解决 NULL 的遗留BUG 2.2 简单实例
【 0. 问题背景 】
0.1 野指针和悬空指针
野指针 悬空指针 产生原因 指针变量未被初始化 就开始使用。对象被删除或内存块被释放后,指向该内存的指针没有被及时设为nullptr,指针指向一块无效内存。 危害 使用野指针可能会导致 程序崩溃 ,因为它可能会随机访问未知内存。 如果继续使用它,可能会操作一些已被操作系统回收或重新分配给其他程序的内存,从而导致 数据损坏或程序异常 。 避免方法 在 定义指针的同时完成初始化操作 ,即便该指针的指向尚未明确,也要将其初始化为空指针。 应该在释放内存或对象销毁后将指针设置为空指针 。
# include <iostream>
using namespace std;
int main ( ) {
int * wildPtr;
int * danglingPtr = new int ( 10 ) ;
delete danglingPtr;
return 0 ;
}
0.2 传统空指针 NULL
传统空指针 的基本语法 C++98/03 标准中,将一个指针初始化为空指针的方式有 2 种:
第一种,可以将指针明确指向 0(0x0000 0000)这个内存空间。大多数操作系统都不允许用户对地址为 0 的内存空间执行写操作,若用户在程序中尝试修改其内容,则程序运行会直接报错。 第二种,可以将指针初始化为 NULL。NULL 并不是 C++ 的关键字,它是 C++ 为我们事先定义好的一个宏,并且它的值往往就是字面量 0(#define NULL 0
)。
int * p = 0 ;
int * p = NULL ;
0.3 传统空指针的局限性
C++ 中将 NULL 定义为字面常量 0,虽然能满足大部分场景的需要,但个别情况下,它会导致程序的运行和我们的预期不符,如下代码所示:
对于 isnull(0) 来说,显然它真正调用的是参数为整形的 isnull() 函数;而对于 isnull(NULL),我们期望它实际调用的是参数为 void*c 的 isnull() 函数,但观察程序的执行结果不难看出,并不符合我们的预期。
# include <iostream>
using namespace std;
void isnull ( void * c) {
cout << "void*c" << endl;
}
void isnull ( int n) {
cout << "int n" << endl;
}
int main ( ) {
isnull ( 0 ) ;
isnull ( NULL ) ;
return 0 ;
}
C++ 98/03 标准中,如果我们想令 isnull(NULL) 实际调用的是 isnull(void* c),就需要对 NULL(或者 0)进行强制类型转换:如此,才会成功调用我们预期的函数。
isnull ( ( void * ) NULL ) ;
isnull ( ( void * ) 0 ) ;
【 1. 基本用法 】
由于 C++ 98 标准使用期间,NULL 已经得到了广泛的应用,出于兼容性的考虑,C++11 标准并没有对 NULL 的宏定义做任何修改,即 传统空指针NULL仍可用但是有BUG 。为了修正 C++ 存在的这一 BUG,C++ 标准委员会最终决定另其炉灶,在 C++11 标准中引入一个新关键字,即 nullptr。 nullptr_t 指针空值类型 是 C++11 新增加的数据类型。nullptr 是 nullptr_t 类型的右值常量,专用于初始化空类型指针,也就是说,nullptr 仅是该类型的一个已定义好可直接使用的实例对象 ,如果需要我们完全定义出多个同 nullptr 完全一样的实例对象。
【 2. nullptr 的应用 】
2.1 nullptr 解决 NULL 的遗留BUG
由于 nullptr 无法隐式转换为整形,而可以隐式匹配指针类型 ,因此执行结果和我们的预期相符。 总之在 C++11 标准下,相比 NULL 和 0,使用 nullptr 初始化空指针可以令我们编写的程序更加健壮。
# include <iostream>
using namespace std;
void isnull ( void * c) {
cout << "void*c" << endl;
}
void isnull ( int n) {
cout << "int n" << endl;
}
int main ( ) {
isnull ( NULL ) ;
isnull ( nullptr ) ;
return 0 ;
}
2.2 简单实例
不同类型的指针变量都可以使用 nullptr 来初始化,编译器分别将 nullptr 隐式转换成 int*、char* 以及 double* 指针类型。
int * a1 = nullptr ;
char * a2 = nullptr ;
double * a3 = nullptr ;