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

C++ 智能指針完整指南:unique_ptr、shared_ptr、weak_ptr 與動態數組管理

     編輯:關於C++

動態內存與手動管理痛點

堆內存(`new`/`delete`)需手動釋放,易發生洩漏(忘記 delete)、二次釋放、懸空指針。異常拋出導致釋放代碼被跳過更是隱患。智能指針通過 RAII(資源獲取即初始化)自動管理生命週期。

shared_ptr:共享所有權

  • 引用計數機制:拷貝/賦值遞增,析構遞減,歸零時 `delete` 對象。
  • `make_shared(args)`:單次分配對象+控制塊,異常安全,性能優於 `new T + shared_ptr`。
  • 自定義刪除器:`shared_ptr(ptr, deleter)`,管理非 `new` 內存(如 `malloc`、C API 句柄、文件描述符)。
  • `get()` 僅供傳遞給不識別智能指針的舊代碼,**不可**用於初始化另一個智能指針。
  • 線程安全:控制塊引用計數原子操作,但對象訪問非線程安全。

unique_ptr:獨占所有權

  • 不可拷貝,可移動(`std::move`)。轉移所有權:`up2 = std::move(up1)`。
  • 無 `make_unique`(C++14 引入),直接 `unique_ptr(new T)`。
  • 自定義刪除器作為模板參數:`unique_ptr`,無運行期開銷(空基類優化)。
  • `release()` 放棄所有權返回裸指針,`reset()` 釋放/重置。
  • 零開銷抽象:大小等同裸指針,釋放調用 `delete`/`delete[]` 內聯。

weak_ptr:弱引用打破循環

  • 不增加引用計數,指向 `shared_ptr` 管理對象。
  • `lock()` 返回 `shared_ptr`(對象存活)或空(已釋放),原子操作。
  • 用於緩存、觀察者模式、父子雙向引用(子持 `weak_ptr` 父)。
  • `expired()` / `use_count()` 輔助檢查。

動態數組管理

  • `unique_ptr`:專用部分特化,支持 `operator[]`,析構調用 `delete[]`。無 `operator*`/`->`。
  • `shared_ptr` (C++17) / `shared_ptr(new T[n], [](T* p){ delete[] p; })` 自定義刪除器。
  • 優先用 `vector` / `string` 替代手動動態數組。

allocator:底層內存分配器

分離「分配原始內存」與「構造對象」:

  • `allocate(n)`:獲取 n 個 T 大小的未構造內存塊。
  • `construct(p, args)`:就地構造(placement new)。
  • `destroy(p)`:顯式調用析構函數。
  • `deallocate(p, n)`:歸還內存。

標準容器內部使用分配器。算法 `uninitialized_copy/fill` 配合分配器實現高效內存操作(如 `vector::reserve`/`resize`/`insert`)。

核心規範(C++ Core Guidelines)

  1. 優先 `make_unique` / `make_shared` 創建。
  2. 函數參數傳 `widget&` / `const widget&` / `widget*`(非所有權),所有權轉移用 `unique_ptr` / `shared_ptr` by value。
  3. 不 `delete get()` 返回指針。
  4. 不 `shared_ptr` 管理非 `new` 內存無自定義刪除器。
  5. 循環引用用 `weak_ptr` 打破。

總結

智能指針是現代 C++ 資源管理基石。`unique_ptr` 獨占零開銷,`shared_ptr` 共享線程安全計數,`weak_ptr` 打破循環。配合 `make_*` 工廠、自定義刪除器、動態數組特化、allocator 底層支持,構建完整、安全、高效的內存管理體系。徹底告別手動 `new`/`delete`,編寫無洩漏、異常安全代碼。

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