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

C++ 重載賦值運算符 (=):深拷貝與資源管理的正確姿勢

     編輯:C++ 基礎

預設賦值行為的隱患

C++ 編譯器為類自動生成的預設賦值運算符執行成員逐一拷貝(member-wise copy)。對於無動態資源的類(如僅含基本型別成員),這完全足夠:

class Demo {
    int m_a, m_b;
public:
    Demo(int a, int b) : m_a(a), m_b(b) {}
    void display() { cout << m_a << ", " << m_b << endl; }
};

int main() {
    Demo obj1(10, 20);
    Demo obj2 = obj1;  // 預設賦值,正常工作
    obj1.display();  // 10, 20
    obj2.display();  // 10, 20
}

指針成員導致的淺拷貝災難

當類包含指針成員並管理動態記憶體時,預設賦值會導致淺拷貝——多個物件共享同一塊記憶體,造成雙重釋放、資料競爭等嚴重錯誤:

class Book {
    double m_price;
    int* m_bookmark;  // 動態陣列
    int m_num;
public:
    Book(double price, int* bookmark, int num) : m_price(price), m_num(num) {
        m_bookmark = new int[num];
        for (int i = 0; i < num; ++i) m_bookmark[i] = bookmark[i];
    }
    void setBookmark(int page, int index) { m_bookmark[index] = page; }
    void display() { /* ... */ }
};

int main() {
    int marks[] = {1, 49, 56, 290};
    Book cpp(68.5, marks, 4);
    Book java = cpp;  // 淺拷貝!java.m_bookmark 指向同一陣列
    java.setBookmark(100, 2);  // 修改影響 cpp!
    cpp.display();  // 書籤被意外修改
}

正確重載賦值運算符:實現深拷貝

核心原則:分配新記憶體、拷貝資料、釋放舊資源、處理自我賦值。

Book& Book::operator=(const Book& b) {
    if (this != &b) {  // 1. 自我賦值檢查
        m_price = b.m_price;
        m_num = b.m_num;

        // 2. 釋放舊資源
        delete[] m_bookmark;

        // 3. 分配新記憶體並深拷貝
        m_bookmark = new int[b.m_num];
        for (int i = 0; i < b.m_num; ++i)
            m_bookmark[i] = b.m_bookmark[i];
    }
    return *this;  // 4. 返回引用支援鏈式賦值
}

關鍵設計要點解析

進階:複製並交換慣用法

現代 C++ 推薦更優雅、異常安全的實現:

Book& Book::operator=(Book b) {  // 參數傳值觸發拷貝建構
    swap(*this, b);              // 交換資源
    return *this;                // b 析構時自動釋放舊資源
}

// 需提供 swap 友元函數
friend void swap(Book& a, Book& b) {
    using std::swap;
    swap(a.m_price, b.m_price);
    swap(a.m_bookmark, b.m_bookmark);
    swap(a.m_num, b.m_num);
}

優點:碼簡潔、強異常安全、自動處理自我賦值。

規則總結

  1. 類管理動態資源(指針、檔案句柄、Socket 等)必須重載賦值運算符
  2. 遵循「三大法則」:若需自定義析構/拷貝建構/賦值,三者通常需同時定義
  3. C++11 起配合移動語意,形成「五大法則」
  4. 優先考慮 std::unique_ptr/std::vector 等 RAII 容器,避免手動管理

結語

重載賦值運算符不僅是語法操作,更是資源管理正確性的核心防線。深拷貝、自我賦值檢查、異常安全、現代慣用法——每一步都關乎程式的健壯性。掌握這些模式,是邁向專業 C++ 開發的必經之路。

  1. 上一篇文章:
  2. 下一篇文章:
  • --热点文章
  • Copyright © 程式碼之家 All Rights Reserved
    要素建議理由
    參數型別const Book&避免拷貝開銷,防止修改源物件
    返回型別Book&支援 a = b = c 鏈式賦值
    自我賦值檢查if (this != &b)防止釋放後再分配導致資料丟失
    資源管理順序先釋放舊,再分配新異常安全:分配失敗時舊資源已釋放,物件處於有效空狀態