正如标题所说,我尝试使用析构函数删除动态分配的矩阵,但出现以下错误:
Exception thrown at 0x78D8DB1B (ucrtbased.dll) in oop.exe: 0xC0000005: Access violation reading location 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;
}
最佳答案
内存地址0xddddddcd
可能是释放后使用错误的迹象,因为 Visual C++ 调试构建标记所有已释放的内存与该内存模式。我在 Linux (clang++ matrice.cc -g -Og -fsanitize=address
) 上使用 ASAN 编译了您的程序,并且能够使用以下堆栈跟踪复制您的问题:
==6670==ERROR: AddressSanitizer: heap-use-after-free on address 0x603000000010 at pc 0x0000004c9a76 bp 0x7fffdcd001b0 sp 0x7fffdcd001a8
READ of size 8 at 0x603000000010 thread T0
#0 0x4c9a75 in Matrice<int>::~Matrice() /tmp/z.cc:44:22
#1 0x4c93c9 in main /tmp/z.cc:54:1
#2 0x7f34a76370b2 in __libc_start_main /build/glibc-YYA7BZ/glibc-2.31/csu/../csu/libc-start.c:308:16
#3 0x41f3cd in _start (/tmp/a.out+0x41f3cd)
0x603000000010 is located 0 bytes inside of 24-byte region [0x603000000010,0x603000000028)
freed by thread T0 here:
#0 0x4c736d in operator delete[](void*) (/tmp/a.out+0x4c736d)
#1 0x4c93c1 in main /tmp/z.cc:53:5
#2 0x7f34a76370b2 in __libc_start_main /build/glibc-YYA7BZ/glibc-2.31/csu/../csu/libc-start.c:308:16
previously allocated by thread T0 here:
#0 0x4c6b1d in operator new[](unsigned long) (/tmp/a.out+0x4c6b1d)
#1 0x4c9536 in Matrice<int>::Matrice(int) /tmp/z.cc:36:19
在第 53 行 (
delete[] matrice[i];
) 调用的析构函数已将其释放后,析构函数似乎在第 44 列第 22 行 ( cout << test
) 读取了某些资源。起初很容易忽略其原因。析构函数被调用了两次,一次在
cout << test
之后。又在 main
结尾.问题如下:函数
friend istream& Matrice::operator>>
接受 Matrice<T>&
类型的参数,这很好,而 operator<<
只需一个 Matrice<T>
按值(value)。这会导致您的 test
实例由 default copy constructor 复制.这是一个问题,因为默认的复制构造函数不会深度复制您的数组,而只是复制指针本身。当
test
的私有(private)拷贝用于operator<<
被破坏,它释放 test
使用的相同数组;因此当 test
的析构函数运行时,它会尝试读取该已释放的数组。这符合 rule of 5/3/0 的概念。 : 如果您的类需要自定义析构函数、自定义复制构造函数或自定义
operator=
,它几乎肯定需要这三个。解决此问题的最简洁方法是使用复制构造函数将矩阵的内容深度复制到一组新数组中。您也可以删除复制构造函数 ( Matrice(Matrice<T> const&) = delete
),但这会使您的类的使用不太灵活。
关于c++ - 尝试使用析构函数删除动态分配的矩阵时出错,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61698074/