衆所周知,C語言使用NULL常量來表示空指針,爲何C++11還要增長新的nullptr來表示空指針呢?函數
1,咱們首先查看NULL的定義:指針
#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL /* in case <stdio.h> has defined it. */
#ifdef __GNUG__
#define NULL __null
#else /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else /* C++ */
#define NULL 0
#endif /* C++ */
#endif /* G++ */
#endif /* NULL not defined and <stddef.h> or need NULL. */
#undef __need_NULL
從上面的定義能夠看出,若是定義了__GNUG__,編譯器NULL其實就是__null,__null是編譯器相關的行爲(要麼是常量0,要麼是 (void *)0),有待進一步研究確認。編譯器
所以,在C語言中,以下定義都是合法的:it
int a = NULL;
char b = NULL;
int *ptr = NULL;
io
2,在C++中,考慮以下重載示例:編譯
void overloaded(int value) {
std::cout << "int value" << std::endl;
}語言
void overloaded(int *ptr) {
std::cout << "int *ptr" << std::endl;
}類型轉換
int main() {
overloaded(NULL); // 歧義,由於NULL既能夠是常量0,也能夠是 void*指針。di
return 0;
}
因爲C++支持函數重載,此時NULL的定義就會帶來歧義,當咱們調用overloaded(NULL);的時候,編譯器沒法確認,究竟是把NULL做爲常量0仍是做爲 (void *)0,所以編譯沒法經過。co
爲了解決這個問題,C++11引入了nullptr常量,該常量是std::nullptr_t類型。std::nullptr_t類型能夠轉換爲任意指針類型(相似於void *,也能夠轉換爲任意指針類型),同時也能夠轉換爲bool類型(用以支持條件判斷 !ptr),可是不能轉換成整型類型。這樣便消除了上面的重載歧義。
overloaded(nullptr); // ok,調用void overloaded(int *ptr);版本
轉換成bool類型示例以下:
int main() {
std::nullptr_t ptr = nullptr;
if (!ptr) { // std::nullptr_t類型轉換成bool類型
std::cout << "nullptr" << std::endl;
}
return 0;
}
3,固然,nullptr只是解決了整型和指針類型的重載問題,對於兩個不一樣指針類型的重載函數,nullptr沒法區分出來:
void overloaded(int *ptr) {
std::cout << "int *ptr" << std::endl;
}
void overloaded(char *ptr) {
std::cout << "char *ptr" << std::endl;
}
int main() {
overloaded(nullptr); // 歧義,依然沒法區分 int *和 char *
return 0;
}
這時候,可使用std::nullptr_t類型,以下:
void overloaded(int *ptr) {
std::cout << "int *ptr" << std::endl;
}
void overloaded(char *ptr) {
std::cout << "char *ptr" << std::endl;
}
void overloaded(std::nullptr_t ptr) {
std::cout << "std::nullptr_t ptr" << std::endl;
}
int main() {
overloaded(nullptr); // ok,輸出 std::nullptr_t ptr
return 0; }