NULL
和 nullptr
都是用於表示空指標的常量,但它們在 C++ 中有一些重要的區別,特別是隨著 C++11 引入了 nullptr
之後,nullptr
成為了更推薦的選擇。以下是兩者的主要區別:
1. 型別
-
NULL
:在 C 和 C++ 中,NULL
是一個宏,通常定義為0
(或(void*)0
),它本質上是整數常量。由於它是一個整數常量,編譯器在使用時可能無法區分空指標和零值的整數,因此可能會引起一些型別轉換的問題。#define NULL 0
NULL
可以隱式轉換為任何指標型別(因為 0 可以被視為空指標)。- 由於其是整數常量,有時可能會導致不明確的轉換。
-
nullptr
:nullptr
是 C++11 中引入的一個關鍵字,專門用於表示空指標。它是一個型別安全的指標常量,具有明確的指標型別 (std::nullptr_t
),並且不能隱式轉換為整數型別。nullptr_t
nullptr
具有明確的型別std::nullptr_t
,並且只能用於指標型別。- 編譯器能夠識別
nullptr
並明確區分它與其他型別(如整數或列舉)。
2. 型別安全
-
NULL
:由於NULL
是一個宏,它通常等於0
,並且0
是一個整數常量,所以NULL
可以隱式轉換為整數型別(這可能導致不明確的型別轉換)。int* p = NULL; // 可以透過隱式轉換 int i = NULL; // 允許將空指標賦值給整數
-
nullptr
:nullptr
是型別安全的,它只能與指標型別匹配,並且不會進行隱式轉換。這消除了由於將NULL
用於整數型別而引起的潛在問題。int* p = nullptr; // 正確 int i = nullptr; // 錯誤:不能將 nullptr 賦值給整數型別
這樣,
nullptr
提供了更強的型別檢查和防止誤用。
3. 用於函式過載
由於 nullptr
具有明確的型別(std::nullptr_t
),它可以幫助解決函式過載時的歧義問題,而 NULL
由於被定義為 0
,可能導致不同型別過載之間的衝突。
例如,如果你有兩個過載函式,一個接受指標,另一個接受整數型別,使用 NULL
可能會導致二義性:
void func(int) {
std::cout << "Integer version\n";
}
void func(char*) {
std::cout << "Pointer version\n";
}
int main() {
func(NULL); // 可能引起二義性:NULL 被視為 0,既可以是 int 型別也可以是指標型別
}
使用 nullptr
可以消除這種二義性,因為它明確表示為空指標:
int main() {
func(nullptr); // 明確呼叫指標版本
}
4. 容易出錯的情況
-
NULL
:如果在某些情況下將NULL
用作整數或其他型別時,可能會導致邏輯錯誤或難以發現的 bug。if (some_pointer == NULL) { // 檢查空指標時沒有問題 // do something } if (some_pointer == 0) { // 0 和 NULL 相同,但 0 可能被錯誤地用作整數 // do something }
-
nullptr
:nullptr
不能與整數或其他型別隱式轉換,因此不容易出錯。if (some_pointer == nullptr) { // 更安全,更明確 // do something }
總結
特性 | NULL | nullptr |
---|---|---|
型別 | 宏,通常等於 0 (整數常量) |
關鍵字,型別為 std::nullptr_t |
型別安全 | 不安全,可能會隱式轉換為整數型別 | 型別安全,不能隱式轉換 |
使用範圍 | 可用於指標和整數型別 | 僅用於指標型別 |
函式過載 | 可能導致過載歧義 | 消除過載歧義 |
C++標準 | 在 C 和 C++ 中都可以使用 | 從 C++11 引入 |
推薦使用 nullptr
- 在 C++ 中,推薦使用
nullptr
代替NULL
,因為它更型別安全,避免了由於隱式轉換引起的潛在問題,並且更清晰地表達了程式碼意圖。