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*)\n"); } void f(int i) { printf("invoke f(int)\n"); } 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是一個編譯時期的常量,其名字是一個編譯時期的關鍵字,能夠為編譯器所識別。