首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 空指針 nullptr 與 void 指針:類型安全的現代最佳實踐

     編輯:關於C++

歷史包袱:0 和 NULL 的缺陷

C/C++ 早期用 0 或 NULL 表示空指針。但 NULL 定義不統一:

  • 部分庫定義為 0 (int)
  • 部分定義為 (void*)0

C 語言中 void* 隱式轉換為任意指針類型,故 (void*)0 無傷大雅。但 C++ 嚴禁隱式 void* 轉換,導致重載決議錯誤:

void f(int);    // #1
void f(int*);   // #2

f(NULL);  // 調用 #1 (NULL=0) 而非 #2!類型安全受損

C++11 解決方案:nullptr

nullptr_t nullptr;  // 關鍵字,類型為 std::nullptr_t
// 特性:
// 1. 隱式轉換為任意指針類型、指向成員指針
// 2. 不隱式轉換為整數類型(包括 bool 需顯式)
// 3. sizeof(nullptr) == sizeof(void*)

代碼示例

#include <iostream>
using namespace std;

void f(int) { cout << "f(int)\n"; }
void f(int*) { cout << "f(int*)\n"; }

int main() {
    f(0);        // f(int)
    f(nullptr);  // f(int*) ✅ 正確選擇指針重載
    f(NULL);     // 視 NULL 定義而定,不可靠

    int* p = nullptr;  // 類型安全初始化
    if (!p) cout << "空指針\n";  // 隱式轉 bool 允許

    // int x = nullptr; // ❌ 編譯錯誤:不能轉為 int
    return 0;
}

void 指針:通用指針類型

  • 可存儲任意對象地址:void* pv = &i;
  • 不能解引用:*pv ❌ 編譯錯誤(無類型信息)
  • 不能算術運算:pv + 1 ❌(未知大小)
  • 需顯式轉換後使用:static_cast(pv)

void* 經典用場景

// 1. 泛型容器/回調上下文
void callback(void* ctx) {
    MyData* data = static_cast(ctx);
    data->process();
}

// 2. C 風格 API 交互 (如 pthread_create)
void* thread_func(void* arg) { ... }

// 3. 內存分配器返回類型
void* malloc(size_t size);
void free(void* ptr);

nullptr vs void* 轉換對比

操作nullptrvoid*
賦值給 T*✅ 隱式✅ 隱式 (C) / ❌ 顯式 (C++)
賦值給整數❌ 編譯錯誤❌ 無意義
解引用❌ 無意義❌ 編譯錯誤
算術運算❌❌
sizeofsizeof(void*)sizeof(void*)

現代 C++ 核心準則

  1. 只用 nullptr 表示空指針,禁用 NULL、0
  2. 盡量避免 void*,改用模板、std::any、std::variant、基類指針
  3. 不得不接觸 C API 時,邊界處 static_cast 封裝,內部不用 void*
  4. 智能指針 (unique_ptr, shared_ptr) 默認構造即為空,無需手動置 nullptr

總結

nullptr 解決了 C++ 歷史遺留的類型安全漏洞,是現代 C++ 代碼的標準配置。void* 是 C 時代產物,現代 C++ 應將其限制在與 C 交互的薄薄邊界層。理解兩者區別,是寫出健壯、可維護 C++ 代碼的基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved