1. 引入nullptr的必要性:
典型的指针初始化是将其指向一个空的位置。比如:
int* my_ptr = 0;
int* my_ptr = NULL;
一般情况下,NULL是一个宏定义。
#undef NULL #if defined(__cplusplus) #define NULL 0 #else #define NULL ((void*)0) #endif
NULL可能被定义为字面常量0,或定义为无类型指针(void*)常量。
一下代码显示了使用NULL引起的意外的行为:
#include <stdio.h> void f(char* c) { printf("invoke f(char*) "); } void f(int i) { printf("invoke f(int) "); } int main() { f(0); f(NULL); f((char*)0); return 0; }
输出为:
invoke f(int)
invoke f(int) // NULL定义0造成的,字面常量0的类型既可以是一个整形,也可以是一个无类型指针(void*)
invoke f(char*)
2.nullptr定义:
typedef decltype(nullptr) nullptr_t;
关于nullptr的常见规则:
(1)所有定义nullptr_t类型的数据都是等价的,行为也是完全一致。
(2)nullptr_t类型数据可以隐式转换成任意一个指针类型。
(3)nullptr_t类型数据不能转换为非指针类型,即使使用reinterpret_cast<nullptr_t>()对的方式也不可以。
(4)nullptr_t类型数据不适用于算术运算表达式
(5)nullptr_t类型数据可以用于关系运算表达式,但仅能与nullptr_t类型数据或者指针类型数据进行比较。
#include <iostream> #include <typeinfo> using namespace std; int main() { char* cp = nullptr; // 不可以转换为整型 // int n1 = nullptr; // int n2 = reinterpret_cast<int>(nullptr); //nullptr 与 nullptr_t 类型可以作比较 nullptr_t nptr; if (nptr == nullptr) { cout << "nullptr_t nptr == nullptr" << endl; } else { cout << "nullptr_t nptr != nullptr" << endl; } if (nptr < nullptr) { cout << "nullptr_t nptr < nullptr" << endl; } else { cout << "nullptr_t nptr !< nullptr" << endl; } //不可以进行算术运算 // nullptr += 1; // nullptr * 5 //以下可以正常运行 sizeof(nullptr); typeid(nullptr); throw(nullptr); return 0; }
3. 规则讨论
c++11标准中,nullptr类型数据所占用的内存空间大小跟void*相同。
sizeof(nullptr_t) == sizeof(void*)
nullptr是一个编译时期的常量,其名字是一个编译时期的关键字,能够为编译器所识别。