參考《深入理解C++11》
NULL是一個宏定義,在傳統C頭文件stddef.h中定義如下:
#undef NULL #ifdef(__cplusplus) #define NULL 0 #else #define NULL ((void *)0) #endif
可以看到,NULL可能被定義為字面常量0,或者定義為無類型指針(void*)常量。這就使得在使用NULL時有些問題:
在main函數中,f(NULL)調用的起始是第二個函數,因為在C++98中,字面常量0具有二義性:既可以是一個整型,也可以是一個無類型指針(void*)。如果想要調用f(char*)的話,需要對字面常量0進行強制類型轉換:(void*)0 然后再調用,否則編譯器總會優先把0看做一個整型常量。
nullptr_t的定義:頭文件:<cstddef>
typedef decltype(nullptr) nullptr_t;
使用nullptr_t時必須包含頭文件:<cstddef>,但是使用nullptr時則不用,因為nullptr是關鍵字。nullptr是有類型的,且僅可以被隱式轉化為指針類型,在編寫C++11代碼時,使用nullptr替換NULL將使得代碼更健壯。
- nullptr:指針空值常量
- nullptr_t:指針空值類型,也就是nullptr的類型,見上面的定義
nullptr_t注意事項:
示例代碼:
char* cp = nullptr; //不可轉換為整型,而任何類型也不能轉換為nullptr_t //以下代碼不能通過編譯 //int n1 = nullptr; //int n2 = reinterpret_cast<int>(nullptr); //nullptr與nullptr_t類型變量可以作比較 //當使用 == <= >=符號比較時返回true 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; //不能轉換為整型或bool類型,以下代碼不能通過編譯 //if(0 == nullptr) //if(nullptr) //不能進行算術運算,以下代碼不能通過編譯 //nullptr += 1; //nullptr *5; //以下操作均可正常運行 size_t size1 = sizeof(nullptr); typeid(nullptr); throw(nullptr);
注:如果上述代碼注釋部分能通過編譯,可能是編譯器版本不夠新,在C++11中不允許上述注釋代碼。
雖然nullptr_t看起來像是個指針類型,但是在把nullptr_t應用於模板中時,模板會把它作為一個普通的類型來進行推導,並不會將其視為T*指針。
template<typename T> void g(T* t){} template<typename T> void h(T t){} int main(int argc, char *argv[]) { g(nullptr); //編譯失敗,nullptr的類型是nullptr_t,而不是指針 g((float*) nullptr);//推導出T=float h(0); //推導出T=int h(nullptr); //推導出T=nullptr_t h((float*)nullptr); //推導出T=float* }