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

C++ 陷阱:傳值調用導致指針雙重釋放

     編輯:C++ 入門

問題代碼

class Text {
private:
    char* str;
public:
    Text() { str = new char[20]; memset(str, 0, 20); }
    void SetText(char* s) { strcpy(str, s); }
    char* GetText() const { return str; }
    ~Text() { delete[] str; }
};

void Print(Text s) {  // 傳值:觸發拷貝構造
    cout << s.GetText() << endl;
} // s 析構,釋放 str

int main() {
    Text t;
    t.SetText("abc");
    Print(t);  // t 的 str 被釋放!
    return 0;  // t 再次析構 → 雙重釋放 → 崩潰
}

根因分析

  1. Print(Text s) 傳值參數 → 編譯器生成默認拷貝構造函數 → 淺拷貝指針 str
  2. 兩個對象 t 和 s 指向同一堆內存
  3. Print 結束,s 析構 → delete[] str
  4. main 結束,t 析構 → 再次 delete[] str → **Heap Corruption**

三種解決方案

1. 實現深拷貝 (三大法則/五大法則)

class Text {
    // ... 
    Text(const Text& other) {           // 拷貝構造
        str = new char[strlen(other.str)+1];
        strcpy(str, other.str);
    }
    Text& operator=(const Text& other) { // 拷貝賦值
        if (this != &other) {
            delete[] str;
            str = new char[strlen(other.str)+1];
            strcpy(str, other.str);
        }
        return *this;
    }
    // C++11 移動語義
    Text(Text&& other) noexcept : str(other.str) { other.str = nullptr; }
    Text& operator=(Text&& other) noexcept {
        if (this != &other) { delete[] str; str = other.str; other.str = nullptr; }
        return *this;
    }
};

2. 傳引用避免拷貝

void Print(const Text& s) {  // const 引用,無拷貝、無修改
    cout << s.GetText() << endl;
}

3. 使用智能指針 / 標準容器 (現代 C++ 首選)

class Text {
    std::string str;  // 自動管理內存,正確拷貝/移動
public:
    void SetText(const char* s) { str = s; }
    const char* GetText() const { return str.c_str(); }
    // 無需手寫構造/析構/拷貝/移動
};

核心原則

  • 管理資源的類必須定義拷貝/移動語義 (Rule of 3/5/0)
  • 優先用標準庫容器/智能指針 替代裸指針手動管理
  • 函數參數傳遞:大對象用 const T&,需修改用 T&,移動語義用 T&&,避免無意義傳值
  • 編譯器警告:開啟 -Wextra -Weffc++ (GCC) 或 /W4 (MSVC) 可捕獲缺失拷貝構造等問題
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved