1. 程式人生 > 實用技巧 >C++11 nullptr與nullptr_t

C++11 nullptr與nullptr_t

  參考《深入理解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*
}