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

C++ 動態記憶體管理全景:從 new/delete 到智慧指標最佳實踐

     編輯:關於C++

C 與 C++ 記憶體管理的本質差異

維度C 風格C++ 風格
分配/釋放 malloc/free new/delete、new[]/delete[]
建構/解構 無(僅原始記憶體) 自動呼叫建構函數與解構函數
失敗處理 回傳 NULL 拋出 std::bad_alloc 異常(可用 nothrow 版本回傳 NULL)
型別安全 需強制轉型 編譯期型別檢查

為什麼需要智慧指標?

手動 new/delete 易因異常、提前 return、複雜流程導致記憶體洩漏:

{
    int* p = new int(5);
    // ... 複雜邏輯 ...
    if (error) throw MyException();  // 此處洩漏!
    delete p;
}

智慧指標採用 RAII(Resource Acquisition Is Initialization):物件建構時獲取資源,離開作用域時自動釋放,無論正常返回或異常拋出皆安全。

主流智慧指標對比

類型所有權語義複製行為適用場景
auto_ptr (C++98, C++11 棄用) 獨占,複製即轉移 複製後來源歸零 已淘汰,易在演算法(如 sort)中導致邏輯錯誤
scoped_ptr (Boost) 獨占,不可複製 編譯期禁止複製/賦值 單一作用域內獨占資源,無轉移需求
shared_ptr (C++11) 共享,引用計數 複製增加計數 多處共享同一資源,生命週期由最後持有者決定
weak_ptr (C++11) 弱引用,不增加計數 可複製,不影響生命週期 打破 shared_ptr 循環引用(雙向鏈表、觀察者模式)
unique_ptr (C++11) 獨占,可移動 禁止複製,支援移動語義 現代 C++ 首選獨占智慧指標,零開銷

核心實作原理剖析

scoped_ptr 簡易實作

template <class T>
class ScopedPtr {
    T* _ptr;
public:
    explicit ScopedPtr(T* ptr = nullptr) : _ptr(ptr) {}
    ~ScopedPtr() { delete _ptr; }
    T& operator*()  { return *_ptr; }
    T* operator->() { return _ptr; }
private:
    ScopedPtr(const ScopedPtr&);            // 禁止複製
    ScopedPtr& operator=(const ScopedPtr&); // 禁止賦值
};

編譯器優化 operator->:ptr->member 直接轉為 ptr.operator->()->member。

shared_ptr 引用計數機制

控制區塊包含:強引用計數、弱引用計數、刪除器、分配器。拷貝構造/賦值時原子增減強引用計數,歸零時呼叫刪除器。

weak_ptr 破解循環引用

// 父節點 shared_ptr 持有子節點,子節點 weak_ptr 持有父節點
struct Node {
    shared_ptr<Node> child;
    weak_ptr<Node> parent;  // 不增加計數
};

lock() 可嘗試提升為 shared_ptr(若物件尚存活)。

shared_ptr 使用陷阱與規範

  • 禁止隱式轉換:構造函數 explicit,必須 shared_ptr<int> p(new int(1))
  • 回傳值必須綁定:return make_shared<T>() 或 shared_ptr<T> tmp(...); return tmp;
  • 勿用 get() 取得原始指標後 delete:導致雙重釋放
  • 優先使用 make_shared:單次分配物件+控制區塊,效率更高、異常安全
  • 避免 shared_ptr 管理陣列:C++17 前無 delete[] 支援,改用 unique_ptr<T[]> 或 vector

總結與建議

  1. 現代 C++(C++11 以降)首選 unique_ptr(獨占)+ shared_ptr/weak_ptr(共享)
  2. 嚴禁裸指標擁有資源所有權
  3. 記憶體洩漏 90% 可由智慧指標自動消除
  4. 循環引用靠 weak_ptr 斷環
  5. 理解 RAII 精髓:資源綁定物件生命週期,編譯器保證釋放
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved