nullptr
nullptr
一、nullptr 基础概念
1.1 为什么需要 nullptr?
在 C++11 之前,NULL被定义为0,会导致了两个主要问题:
- 类型不安全性:
0既可以是整数,也可以是空指针 - 函数重载二义性:无法区分
int和指针类型的重载
// C++ 中 NULL 的本质#ifdef__cplusplus#defineNULL0// C++:NULL 就是 0#else#defineNULL((void*)0)// C:NULL 是 void* 类型#endif1.2 nullptr 的特性
| 特性 | 说明 |
|---|---|
| 类型安全 | nullptr有独立的类型std::nullptr_t |
| 可隐式转换 | 可转换为任何指针类型 |
| 不能转换为整数 | 不能赋值给int等整数类型 |
| 常量性 | 是常量,不能修改 |
| 大小 | sizeof(nullptr)==sizeof(void*) |
二、C 与 C++ 中 NULL 的区别
2.1 C 语言中的 NULL
// C 中 NULL 是 void* 类型#defineNULL((void*)0)intmain(){inta=10;void*vp=&a;// C 允许 void* 隐式转换为其他指针类型int*ip=vp;// 可以char*cp=vp;// 可以// NULL 可以直接赋值int*p=NULL;// 可以return0;}2.2 C++ 中的 NULL
// C++ 中 NULL 是 0// C++的严格类型检查,不能直接将void* 类型的指针赋值给其他类型的指针,所以NULL定义为 0#defineNULL0intmain(){inta=10;void*vp=&a;// C++ 不允许 void* 隐式转换int*ip=vp;// 错误!!!int*ip=(int*)vp;// 必须显式转换// NULL 实际上是 0int*p=NULL;// 可以(0 可赋值给指针)intx=NULL;// 可以(0 可赋值给整数)return0;}三、NULL 导致的二义性问题
3.1 函数重载的二义性
#include<iostream>usingnamespacestd;voidfun(inta){cout<<"fun(int a)"<<endl;}voidfun(char*p){cout<<"fun(char* p)"<<endl;}intmain(){fun(0);// 调用 fun(int)fun(NULL);// 调用 fun(int)!因为 NULL 是 0// 问题:程序员可能期望调用 fun(char*)return0;}输出:
fun(int a) fun(int a)3.2 更多二义性示例
voidfunc(intx){cout<<"int"<<endl;}voidfunc(longx){cout<<"long"<<endl;}voidfunc(void*p){cout<<"pointer"<<endl;}intmain(){func(0);// 调用 func(int)func(NULL);// 调用 func(int) 或 func(long)?二义性!// 某些编译器可能产生编译错误return0;}四、nullptr 的使用
4.1 基本用法
#include<iostream>usingnamespacestd;intmain(){// nullptr 可以直接赋值给 int* 和 char* 等类型int*p=nullptr;// 可以char*cp=nullptr;// 可以double*dp=nullptr;// 可以void*vp=nullptr;// 可以// nullptr 不能转换为整数// int x = nullptr; // 错误!!!// int y = 0; // 正确// nullptr 是常量,不可修改// nullptr = 0; // 错误!!!// 判空比较if(p==nullptr){cout<<"p is null pointer"<<endl;}// sizeof nullptrcout<<"sizeof(nullptr) = "<<sizeof(nullptr)<<endl;cout<<"sizeof(void*) = "<<sizeof(void*)<<endl;// 相同return0;}4.2 解决函数重载二义性
#include<iostream>usingnamespacestd;voidfun(inta){cout<<"fun(int a)"<<endl;}voidfun(char*p){cout<<"fun(char* p)"<<endl;}intmain(){fun(0);// 调用 fun(int)fun(nullptr);// 调用 fun(char*) 明确是指针版本// fun(NULL); // 可能产生二义性return0;}输出:
fun(int a) fun(char* p)五、nullptr_t 类型
5.1 std::nullptr_t
nullptr的类型是std::nullptr_t,定义在<cstddef>中。
#include<cstddef>#include<iostream>usingnamespacestd;intmain(){// nullptr 的类型decltype(nullptr)np=nullptr;// np 是 nullptr_t 类型// nullptr_t 可以转换为任何指针类型int*p=np;char*cp=np;// nullptr_t 只能转换为指针类型// int x = np; // 错误!!!// 函数重载 nullptr_tautofunc=[](nullptr_t){cout<<"nullptr_t parameter"<<endl;};func(nullptr);// 调用 nullptr_t 版本return0;}5.2 nullptr_t 的特性
#include<cstddef>#include<iostream>usingnamespacestd;intmain(){// 所有 nullptr_t 实例都等价nullptr_t np1=nullptr;nullptr_t np2=nullptr;// 可以比较if(np1==np2){cout<<"equal"<<endl;// 输出 equal}// 可以转换为 boolif(!np1){cout<<"null"<<endl;// 输出 null}// 可以作为函数参数类型autocheck=[](nullptr_t np){cout<<"Received nullptr"<<endl;};check(nullptr);return0;}六、nullptr 与 NULL 对比
6.1 类型对比
| 特性 | nullptr | NULL(C++) |
|---|---|---|
| 类型 | std::nullptr_t | int(本质是 0) |
| 可赋值给指针 | 可以 | 可以 |
| 可赋值给整数 | 不可以 | 可以 |
| 函数重载区分 | 可以区分指针和整数 | 无法区分 |
| 类型安全 | 类型安全 | 类型不安全 |
| 可读性 | 明确表示空指针 | 可能是整数0 |
