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

C++ Matrix 類內存管理錯誤深度剖析:static 臨時對象導致 Double Free

     編輯:程式設計綜合問答

錯誤現場還原

Matrix& Matrix::operator-(const Matrix &m) {
    // ...
    static Matrix temp(row_n, column_n); // 錯誤根源:static 靜態局部變量
    // ... 計算 ...
    return temp; // 返回靜態對象引用
}

// 主函數調用
Matrix ma1, temp;
temp = ma1 - ma5; // 觸發 operator=,雙方嘗試釋放同一塊 static 內存

三大致命缺陷

  1. static 臨時對象生命週期錯誤:static Matrix temp 僅初始化一次,全程共享同一塊內存。多次調用 operator- 會覆蓋數據,返回引用指向同一對象。
  2. 賦值運算符雙重釋放:temp = ma1 - ma5 調用 operator=,左側 temp 釋放舊內存,右側臨時對象(其實是同一個 static temp)隨後析構再次釋放 → Double Free。
  3. 拷貝構造/賦值未實現深拷貝:類包含裸指針 int** element,編譯器生成的淺拷貝導致多個對象指向同一堆內存。

正確實現模式

方案一:返回值優化 (RVO/NRVO) + 非 static 臨時對象 (C++98/11 通用)

Matrix Matrix::operator-(const Matrix &m) const { // 返回值而非引用
    if (/*尺寸不匹配*/) throw std::invalid_argument("Size mismatch");
    Matrix result(row_n, column_n); // 棧上創建臨時對象
    for (int i=0; i<row_n; ++i)
        for (int j=0; j<column_n; ++j)
            result.element[i][j] = element[i][j] - m.element[i][j];
    return result; // C++11 起保證移動語義/編譯器優化消除拷貝
}

方案二:現代 C++ 棄用裸指針,用 std::vector (強烈推薦)


class Matrix {
    std::vector<std::vector<double>> data_;
public:
    Matrix(int r, int c) : data_(r, std::vector<double>(c)) {}
    Matrix operator-(const Matrix& m) const {
        Matrix res(rows(), cols());
        for (int i=0; i<rows(); ++i)
            for (int j=0; j<cols(); ++j)
                res.data_[i][j] = data_[i][j] - m.data_[i][j];
        return res;
    }
    // 無需手寫 析構/拷構/賦值/移構/移賦,編譯器自動生成正確版本
};

調試技巧

  • 開啟 AddressSanitizer (ASan):g++ -fsanitize=address -g / VS /fsanitize=address,運行即可精準定位 Double Free/Use-after-free 堆棧。
  • 重載 new/delete 打印分配釋放日誌,觀察對象生命週期。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved