首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 更多程式語言 >> 程式設計綜合問答

C++ Primer 第 5 版練習 13.8 複制指派運算子深度解析:delete 後為何能再賦值?

     編輯:程式設計綜合問答

C++ Primer 練習 13.8 要求實作 HasPtr 的複制指派運算子,關鍵程式碼 delete ps; ps = new_ps; 讓許多初學者困惑:ps 指向的記憶體已釋放,為何還能賦值新位址?本文從指標本質、記憶體生命週期、RAII 原則三個層面徹底釐清。

題目程式碼片段

HasPtr& HasPtr::operator=(const HasPtr &hp) {
    std::string *new_ps = new std::string(*hp.ps); // 1. 深層複製資料
    delete ps;                                     // 2. 釋放舊資源
    ps = new_ps;                                   // 3. 指標指向新資源
    i = hp.i;
    return *this;
}

核心觀念:指標 ≠ 它指向的記憶體

概念說明比喻
ps (指標變數)儲存記憶體位址的「變數」,本身佔用堆疊空間 (通常 8 位元組)門牌號碼紙條
*ps (指向的物件)堆積區的一塊記憶體區域,存放實際資料 (std::string)房子本身
delete ps歸還「房子」給作業系統,「門牌號碼紙條」仍在手上,但內容已失效拆除房子,紙條留著
ps = new_ps在「門牌號碼紙條」上填寫新房子的地址換張新門牌

逐行執行流程圖解


執行前:          ps ──────> [舊 string 物件 @ 0x1000]
                    new_ps ──> [新 string 物件 @ 0x2000] (剛 new 出來)

delete ps;        釋放 0x1000 記憶體,ps 仍儲存 0x1000 (懸空指標)
                    ps ──────> [已釋放記憶體 @ 0x1000] ⚠️
                    new_ps ──> [新 string 物件 @ 0x2000]

ps = new_ps;      ps 變數內容更新為 0x2000
                    ps ──────> [新 string 物件 @ 0x2000] ✅
                    new_ps ──> [新 string 物件 @ 0x2000]

為什麼要先 new 再 delete?(強制例外安全)

  • 若先 delete ps 再 new,new 拋出 bad_alloc 時,ps 已成懸空指標,物件進入不可恢復狀態。
  • 先 new 成功才 delete 舊資源,確保「要么複製成功,要么維持原狀」,滿足強制例外安全保證。

現代 C++ 改寫:智慧指標消除手動管理

#include 
#include 

class HasPtr {
    std::shared_ptr ps; // 共享擁有權,自動引用計數
    int i;
public:
    HasPtr(const std::string &s = "") : ps(std::make_shared(s)), i(0) {}
    // 編譯器自動產生的 複制建構/指派/解構 皆正確 (Rule of Zero)
    // 無需手寫 operator=、~HasPtr()、copy ctor
};

常見誤區 Q&A

誤區澄清
delete ps 會把 ps 變成 nullptr不會。delete 僅釋放記憶體,指標變數值不變,成為懸空指標。
ps = new_ps 會複製字串內容不會。僅複製指標值 (位址),兩指標指向同一物件 (共享)。
指標變數本身在堆積區區域變數指標在堆疊;new 出來的物件才在堆積。

總結

delete ps 釋放的是「被指向的記憶體」,而非「指標變數本身」。指標變數 ps 依然存在於堆疊,隨時可接受新位址賦值。理解「指標與被指物件分離」是掌握 C++ 記憶體管理的關鍵。現代 C++ 建議優先使用 std::shared_ptr/std::unique_ptr 實踐 RAII,徹底避免手動 new/delete 的風險。

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