錯誤現場還原
Matrix& Matrix::operator-(const Matrix &m) {
// ...
static Matrix temp(row_n, column_n); // 錯誤根源:static 靜態局部變量
// ... 計算 ...
return temp; // 返回靜態對象引用
}
// 主函數調用
Matrix ma1, temp;
temp = ma1 - ma5; // 觸發 operator=,雙方嘗試釋放同一塊 static 內存
三大致命缺陷
- static 臨時對象生命週期錯誤:
static Matrix temp 僅初始化一次,全程共享同一塊內存。多次調用 operator- 會覆蓋數據,返回引用指向同一對象。
- 賦值運算符雙重釋放:
temp = ma1 - ma5 調用 operator=,左側 temp 釋放舊內存,右側臨時對象(其實是同一個 static temp)隨後析構再次釋放 → Double Free。
- 拷貝構造/賦值未實現深拷貝:類包含裸指針
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 打印分配釋放日誌,觀察對象生命週期。