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

C++ 複製構造函數與賦值運算符重載:深拷貝完整指南

     編輯:C++ 入門

問題背景

類別包含指標成員時,預設複製構造函數與賦值運算符執行「淺拷貝」(僅複製指標值),導致多物件共用同一塊堆記憶體,析構時雙重釋放或存取已釋放記憶體。

演示錯誤代碼


class C {
public:
    C(int v) { ptr = new int(v); val = v; }
    ~C() { delete ptr; }
    void Del() { val=0; delete ptr; }
    int *ptr; int val;
};
int main() {
    C c1(2), c2(3);
    c2 = c1;          // 淺拷貝:c2.ptr 指向 c1.ptr 同一記憶體
    c1.Del();         // 釋放記憶體
    // c2.ptr 成懸空指標,後續存取 UB
}

解決方案:三大法則

  1. 複製構造函數:C(const C& other) 深拷貝指標指向的資料。
  2. 賦值運算符:C& operator=(const C& other) 釋放舊資源、深拷貝新資源、自我賦值檢查。
  3. 析構函數:正確釋放資源。

正確實作


class C {
public:
    C(int v) : ptr(new int(v)), val(v) {}
    ~C() { delete ptr; }

    // 複製構造函數
    C(const C& other) : ptr(new int(*other.ptr)), val(other.val) {}

    // 賦值運算符
    C& operator=(const C& other) {
        if (this != &other) {        // 自我賦值檢查
            delete ptr;              // 釋放舊資源
            ptr = new int(*other.ptr); // 深拷貝
            val = other.val;
        }
        return *this;
    }

    void Del() { val=0; delete ptr; ptr=nullptr; }
    int *ptr; int val;
};

關鍵細節

  • 複製構造函數初始化列表直接深拷貝,不調用 operator=(避免對未初始化 ptr 刪除)。
  • 賦值運算符順序:先檢查自我賦值 → 刪除舊資源 → 分配新資源 → 複製值 → 返回 *this。
  • 現代 C++ (C++11) 建議改用 std::unique_ptr 或 std::shared_ptr 自動管理資源,避免手寫三大法則。

驗證測試


int main() {
    C c1(2), c2(3);
    c2 = c1;          // 深拷貝
    c1.Del();         // 僅影響 c1
    printf("c2.ptr=%p val=%d\n", c2.ptr, *c2.ptr);  // 正常輸出 2
    return 0;
}

總結

管理動態資源的類別必須遵循「三大法則」(C++11 後為「五大法則」含移動語意)。深拷貝確保物件語意獨立,避免資源管理錯誤。現代 C++ 應優先使用智慧指標與標準容器,讓編譯器自動生成正確的特殊成員函數。

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