C++11 nullptr與nullptr_t
阿新 • • 發佈:2020-08-13
參考《深入理解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* }