如标题所述,我尝试使用析构函数删除动态分配的矩阵,并且出现以下错误:
oop.exe中的0x78D8DB1B(ucrtbased.dll)引发异常:0xC0000005: 访问冲突读取位置0xDDDDDDCD。
这是我尝试运行的代码。
#include <iostream>
using namespace std;
template<class T>
class Matrice
{
private:
int marime;
T** matrice;
public:
Matrice(int marime);
~Matrice();
friend istream& operator>>(istream& in,Matrice<T>& mat) {
for (int i = 0; i < mat.marime; i++) {
for (int j = 0; j < mat.marime; j++) {
cout << "Matrice[" << i << "][" << j << "]: ";
in >> mat.matrice[i][j];
}
}
return in;
}
friend ostream& operator<<(ostream& out,Matrice<T> mat) {
for (int i = 0; i < mat.marime; i++) {
cout << endl;
for (int j = 0; j < mat.marime; j++) {
out << mat.matrice[i][j]<<" ";
}
}
return out;
}
};
template<class T>
Matrice<T>::Matrice(int marime) {
this->marime = marime;
matrice = new T * [marime];
for (int i = 0; i < marime; i++) {
matrice[i] = new T[marime];
}
}
template<class T>
Matrice<T>::~Matrice() {
for (int i = 0; i < marime; i++) {
delete[] matrice[i]; //Here is where i get the error.
}
delete[] matrice;
}
int main()
{
Matrice<int> test(3);
cin >> test;
cout << test;
}
The memory address
0xddddddcd
is a likely sign of a use-after-free bug, since Visual C++ debug builds tag all freed memory with that memory pattern. I compiled your program using ASAN on Linux (clang++ matrice.cc -g -Og -fsanitize=address
) and was able to replicate your issue with the following stacktrace:It looks like some resource is read by the destructor at line 44 col 22 (
delete[] matrice[i];
) after it has already been freed by a destructor called from line 53 (cout << test
).The reason for this is easy to miss at first. The destructor was being called twice, once after
cout << test
and again at the end ofmain
.The issue is as follows: the function
friend istream& Matrice::operator>>
takes a parameter of typeMatrice<T>&
, which is fine, whileoperator<<
takes just aMatrice<T>
by value. This causes your instance oftest
to be copied, by the default copy constructor. This is a problem, because the default copy constructor doesn't deep-copy your arrays, but it just copies the pointers themselves.When the private copy of
test
used inoperator<<
is destructed, it frees the same arrays that were used bytest
; thus when the destructor oftest
runs, it tries to read that already-freed array.This hits the notion of the rule of 5/3/0: if your class requires a custom destructor, a custom copy constructor, or a custom
operator=
, it almost certainly needs all three. The cleanest way to resolve this would be a copy constructor that deep-copies the contents of the matrix to a new set of arrays. You could alternatively delete the copy constructor (Matrice(Matrice<T> const&) = delete
), but this makes your class a little less flexible to use.