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

C++ vector 存放自定義對象導致內存洩漏?根因與修復全解析

     編輯:程式設計綜合問答

問題代碼回顧

class yitem {
public:
    yitem(const char *s1): m_data(s1) { m_str = new string("abc"); }
    ~yitem() { delete m_str; }
    string & get_data() { return m_data; }
private:
    string m_data;
    string *m_str = nullptr;
};

int main() {
    vector<yitem> v1;
    yitem a("A");
    v1.push_back(a); // 這裡發生拷貝構造
    return 0;
}

Valgrind 報告內存洩漏,原因在於 `yitem` 包含裸指針 `m_str`,但未定義拷貝構造函數與拷貝賦值運算符。

核心原理

`vector::push_back` 會觸發元素的拷貝構造。編譯器自動生成的默認拷貝構造僅執行淺拷貝(逐位複製),導致新對象的 `m_str` 指向同一塊堆內存。當臨時對象 `a` 析構時 `delete m_str` 釋放內存,vector 內的對象持有野指針;程序結束 vector 析構再次 `delete` 同一地址 → 雙重釋放/內存洩漏/未定義行為。

修復方案:遵循「三/五法則」

方案一:實現深拷貝(C++98 風格)

class yitem {
public:
    yitem(const char *s1): m_data(s1), m_str(new string("abc")) {}
    // 拷貝構造
    yitem(const yitem& other): m_data(other.m_data), m_str(new string(*other.m_str)) {}
    // 拷貝賦值
    yitem& operator=(const yitem& other) {
        if (this != &other) {
            m_data = other.m_data;
            *m_str = *other.m_str;
        }
        return *this;
    }
    ~yitem() { delete m_str; }
    // ...
};

方案二:使用智能指針(現代 C++ 推薦)

#include <memory>
class yitem {
    string m_data;
    unique_ptr<string> m_str; // 或 shared_ptr
public:
    yitem(const char *s1): m_data(s1), m_str(make_unique<string>("abc")) {}
    // 無需顯式聲明析構/拷貝/移動,unique_ptr 禁止拷貝,vector 需存放 unique_ptr 或用 shared_ptr
};

若 vector 必須存值類型,改用 `shared_ptr` 並定義拷貝行為;或直接將 `string m_str` 作為值成員,消除裸指針才是最佳實踐。

最佳實踐建議

  • 優先使用標準庫容器、智能指針、值語義類型,避免手動 `new/delete`。
  • 若類管理資源(指針、句柄、鎖),必須顯式聲明/刪除:析構函數、拷貝構造、拷貝賦值、移動構造、移動賦值(C++11 五法則)。
  • 啟用編譯器警告 `-Wall -Wextra -Weffc++`,靜態分析工具(Clang-Tidy、Cppcheck)可自動檢測此類問題。

掌握資源管理語義,才能寫出無洩漏、異常安全的 C++ 代碼。

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