NULL和nullptr

轉自:http://blog.kingsamchen.com/archives/697

0.NULL的前世今生

對於C和C++程序員來說,一定不會對NULL感到陌生。但是C和C++中的NULL卻不等價(別驚訝,這是真的)。

NULL表示指針不指向任何對象,但是問題在於,NULL不是關鍵字,而只是一個宏定義(macro)。

在C中,習慣將NULL定義爲void*指針值0:


#define NULL (void*)0


但同時,也允許將NULL定義爲整常數0

An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.55) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.

在C++中,NULL卻被明確定義爲整常數0:


#define NULL 0


A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero.

導致不同定義的根本原因是:隱式類型轉換(implicit conversion)。

C的定義使得存在void*到0的隱式類型轉換,而宏觀表現則是,void*指針可以直接賦值給其他的指針類型

int* ptr = 0;

int* pptr = (void*)0; // both are legal in c


但是C++卻不支持void*到其他類型的隱式轉換,所以上面的代碼在C++中並不能全部通過編譯。

1.C++的解釋

爲什麼C++在NULL上選擇不完全兼容C?原因和C++的重載函數有關。

C++通過搜索匹配參數的機制,試圖找到最佳匹配(best-match)的函數,而如果繼續支持void*的隱式類型轉換,則會帶來語義二義性(syntax ambiguous)的問題。

考慮下面兩個重載函數:

void foo(int i);

void foo(char* p)

 

foo(NULL); // which is called?


編譯器同時找到了兩個最佳匹配,以至於連編譯器都不知道選擇哪個。

爲了消除混亂,C++纔會將NULL定義爲整常數0。

但是,這麼做又帶來了另一個問題:NULL和整型發生了重疊。

2.C++的選擇

爲了徹底解決NULL帶來的問題,C++0x標準引入了一個新的關鍵字:nullptr。

nullptr是一個很神奇的關鍵字,他被定義爲std::nullptr_t類型,這是一個泛指針類型(這個術語是我自己加的-.-),支持到其他指針類型的自動轉換。並且不支持到除了bool類型以外的整型的轉換。

由於nullptr具有類型,且支持到任何兼容的指針類型的轉換,所以對於上述重載函數的調用,編譯器會很明確的選擇第二個函數。

不過,引入新關鍵字並不代表解決了一切問題。其代價也很明顯:向後兼容性/習慣性和編譯器的支持程度。

C++0x中保留了原來的NULL,所以舊的代碼也可以通過編譯。並且爲了和C保持最大程度的兼容,在一段時間內,NULL都應該是支持的。

至於程序員對於nullptr的接受程度,那隻能另當別論。

對於編譯器,Visual Studio 2010已經開始支持C++0x中的大部分特性,自然包括nullptr。而VS2010之前的版本,都不支持此關鍵字。

Codeblocks10.5附帶的G++ 4.4.1不支持nullptr,升級爲4.6.1後可支持nullptr(需開啓-std=c++0x編譯選項)

其餘編譯器對於nullptr的支持就不是太清楚了。有需要的可自行翻閱Wiki。

考慮到目前的編譯環境,用nullptr全面代替NULL不太現實,不過可以在文件頭加入說明或使用預編譯。

發佈了10 篇原創文章 · 獲贊 21 · 訪問量 14萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章