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

C++ 拷貝構造函數與賦值運算符深度解析:含動態資源類的正確實現

     編輯:關於C++

核心原則

**包含動態分配成員(指針、句柄等)的類,必須提供拷貝構造函數並重載賦值運算符**,實現深拷貝,避免雙重釋放、資源洩漏、邏輯錯誤。

示例類:動態緩衝區管理


class CExample {
public:
    CExample() : pBuffer(nullptr), nSize(0) {}
    ~CExample() { delete[] pBuffer; }
    void Init(int n) { pBuffer = new char[n]; nSize = n; }
private:
    char* pBuffer;
    int nSize;
};

一、拷貝構造函數

調用時機

  1. 用現有對象**初始化**新對象:`CExample obj2 = obj1;` 或 `CExample obj2(obj1);`
  2. 對象**按值傳參**給函數:`void func(CExample obj); func(obj1);`
  3. 函數**按值返回**局部對象:`CExample func() { CExample t; return t; }`

默認行為缺陷

逐位複製指針值 → 兩對象共享同一塊堆內存 → 析構時雙重 `delete[]` → 崩潰。

正確實現


class CExample {
public:
    // ... 原有代碼 ...
    CExample(const CExample& rhs);  // 聲明
private:
    char* pBuffer;
    int nSize;
};

CExample::CExample(const CExample& rhs) {
    nSize = rhs.nSize;
    pBuffer = new char[nSize];
    memcpy(pBuffer, rhs.pBuffer, nSize);
}

二、賦值運算符重載

調用時機

已構造對象間的賦值:`obj3 = obj1;`(obj3 已存在,需釋放舊資源)。

默認行為缺陷

指針值覆蓋 → 舊內存洩漏、新內存共享 → 雙重釋放。

正確實現(強異常安全)


class CExample {
public:
    // ...
    CExample& operator=(const CExample& rhs);
};

CExample& CExample::operator=(const CExample& rhs) {
    if (this != &rhs) {  // 自賦值檢查
        char* tmp = new char[rhs.nSize];  // 先分配新,再釋放舊
        memcpy(tmp, rhs.pBuffer, rhs.nSize);
        delete[] pBuffer;
        pBuffer = tmp;
        nSize = rhs.nSize;
    }
    return *this;
}

三、拷貝構造委托賦值運算符


CExample::CExample(const CExample& rhs) : pBuffer(nullptr), nSize(0) {
    *this = rhs;  // 復用賦值邏輯
}

優點:邏輯集中維護。缺點:默認構造+賦值比直接初始化稍慢(可忽略)。

現代 C++ 改進:Copy-and-Swap / Rule of Five


#include <algorithm>
#include <utility>

class CExample {
public:
    CExample() : pBuffer(nullptr), nSize(0) {}
    CExample(const CExample& rhs) : pBuffer(nullptr), nSize(0) { *this = rhs; }
    CExample(CExample&& rhs) noexcept : pBuffer(rhs.pBuffer), nSize(rhs.nSize) {
        rhs.pBuffer = nullptr; rhs.nSize = 0;
    }
    CExample& operator=(CExample rhs) noexcept {  // by value!
        swap(*this, rhs);
        return *this;
    }
    ~CExample() { delete[] pBuffer; }
    friend void swap(CExample& a, CExample& b) noexcept {
        using std::swap;
        swap(a.pBuffer, b.pBuffer);
        swap(a.nSize, b.nSize);
    }
private:
    char* pBuffer;
    int nSize;
};

Rule of Zero:最佳選擇


class CExample {
    std::vector<char> buffer_;  // 自動管理內存,無需任何特殊函數
public:
    void Init(int n) { buffer_.resize(n); }
    // 編譯器合成的拷貝/移動/析構全正確!
};

總結對比

場景必須實現推薦模式
手動管理動態內存拷貝構造、賦值、析構、移動構造、移動賦值Copy-and-Swap
用 RAII 類型管理資源無(Rule of Zero)直接用 vector/unique_ptr/string
禁止拷貝刪除拷貝構造/賦值`= delete` (C++11) 或私有化 (C++98)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved