1. 空指针
在谈nullptr之前,我们先聊聊C++中的空指针:
在指针变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。赋为 NULL 值的指针被称为空指针。NULL 指针是一个定义在标准库中的值为零的常量。例如:
#include <iostream>
//程序将输出:ptr 的值是 0
using namespace std;
int main ()
{
int *ptr = NULL;
// int *ptr = 0;
cout << "ptr 的值是 " << ptr ;
return 0;
}
在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。如需检查一个空指针,可以使用 if 语句,如下所示:
if(ptr) /* 如果 ptr 非空,则完成 */
if(!ptr) /* 如果 ptr 为空,则完成 */
//个人常用的方式:
if(ptr!=NULL) /* 如果 ptr 非空,则完成 */
if(ptr==NULL) /* 如果 ptr 为空,则完成 */
所以,综上所述,声明一个空指针可有两种方式:。
此处对NULL和常数0进行一些整理:
- NULL到底是什么?NULL的实质是一个在标准库头文件<stddef.h>中定义的宏。
- 它的值是多少?C/C++标准规定:它的值是一个空指针常量(null pointer constant),由实现定义。
- 什么样的值才能称之为空指针常量?C语言中常数0和都是空指针常量;C++中(暂且忽略C++11)常数0是,而不是。
其实我们查看对NULL的定义即可明白:
if defined(__cplusplus)
define NULL 0 // C++中使用0作为NULL的值
else
define NULL ((void *)0) // C中使用((void *)0)作为NULL的值
endif
2. nullptr
通过上述介绍,我们不难看出,在编程的世界里0有双重的角色,可以表示整数零,也可以表示一个空指针。在C语言中,通过预编译宏NULL,可以区分0表示的是零还是(void*)0。但是,在C++的世界中,这样是不可以的。加之C++中允许函数重载,这便对空指针的声明产生了影响,例如:
void foo(char *);
void foo(int);
如果把NULL定义为0,那么foo(NULL)将调用哪个函数呢?
#include <stddef.h>
void foo(int) {} // #1
void foo(char*) {} // #2
int main() {
foo(NULL); // 调用#1还是#2?
}
从字面上来讲,NULL是个空指针常量,我们可能会觉得:既然是个指针,那么应该调用#2。但事实上调用的却是#1,因为C++中NULL扩展为常数0,它是int型。
为了解决常数0既是整数常量,也是空指针常量这样的二义性问题,C++11引入了另一个关键字nullptr,作为一个空指针。例如:
char *pc = nullptr; // OK
int *pi = nullptr; // OK
bool b = nullptr; // OK. b is false.
int i = nullptr; // error
foo(nullptr); // calls foo(char *), not foo(int);