读取类的析构函数中的位置时发生访问冲突

Access violation reading location in a destructor of a class

本文关键字:访问冲突 析构函数 读取 位置      更新时间:2023-10-16

我已经构建了Graph类、一个构造函数和一个析构函数。我的问题是:当我编译这个代码时,我在delete [] mat[i];行得到一个错误,错误是"读取位置0xDDDDDCD的访问冲突"我不知道我做错了什么。我的意思是,我只删除我动态分配的内存。后期编辑:即使我用这个代替我的方法:

Graph(int nr_noduri) {

this->nr_noduri = nr_noduri;
mat = new bool* [nr_noduri];
for (int i = 0; i < nr_noduri; i++) {
mat[i] = new bool[nr_noduri];
}
for (int i = 0; i < nr_noduri; i++) {
for (int j = 0; j < nr_noduri; j++) {
mat[i][j] = 0;
}
}
}

我的代码是:

#include <iostream>
#include <cstdlib>
using namespace std;
class Graph {
bool** mat;
int nr_noduri;
public:
Graph(int nr_noduri) {
this->nr_noduri = nr_noduri;
mat = (bool**)calloc(nr_noduri, sizeof(bool*));
for (int i = 0; i < nr_noduri; i++) {
mat[i] = (bool*)calloc(nr_noduri, sizeof(bool));
}
}
int size() {
return nr_noduri;
}
void addArc(int v, int w) {
if (v < nr_noduri && w < nr_noduri) {
mat[v][w] = true;
}
else cout << "Not enough nodes !" << endl;
}
bool isArc(int v, int w) {
return (mat[v][w] == true);
}
void print() {
for (int i = 0; i < nr_noduri; i++) {
cout << endl;
for (int j = 0; j < nr_noduri; j++) {
cout << mat[i][j] << " ";
}
}
cout << endl;
}
~Graph() {
//cout << nr_noduri;
for (int i = 0; i < nr_noduri; i++) {
delete [] mat[i];
}
delete[] mat;
}
friend void dfs(Graph g, int v, bool vazut[]);
};
void dfs(Graph g, int v, bool vazut[]) {
int w;
vazut[v] = true;
for (w = 0; w < g.size(); w++) {
if (g.isArc(v, w) && !vazut[w]) {
cout << v << "->" << w;
dfs(g, w, vazut);
}
}
}

int main() {
int nr_noduri;
cin >> nr_noduri;
Graph v(nr_noduri);
v.print();
v.addArc(1, 2);
v.addArc(2, 5);
cout << v.isArc(1, 2) << endl;
v.print();
bool vazut[100];
dfs(v, 1, vazut);
return 0;
}

您不能使用delete来解除分配由calloc(或任何malloc函数族(分配的内存。请改用new来分配内存。

Graph(int nr_noduri) {
this->nr_noduri = nr_noduri;
mat = new bool*[nr_noduri];
for (int i = 0; i < nr_noduri; i++) {
mat[i] = new bool[nr_noduri];
}
}

更好的是,使用std::vector<std::vector<bool>>来保存数据。

class Graph {
std::vector<std::vector<bool>> mat;
Graph(int nr_noduri) : mat(nr_noduri, std::vector<bool>(nr_noduri) {}
...
};

此行:

void dfs(Graph g, int v, bool vazut[])

具有按值传递的第一个参数g,因此将是传入的Graph的临时副本。如果Graph没有正确的复制语义,则对dfs的调用将导致未定义的行为。

CCD_ 12包含指向动态分配的存储器的成员CCD_。此外,Graph有一个析构函数,它在这个内存上发出delete []。因此,当Graph被复制时,mat指针也被复制。现在有两个mat指针指向同一内存。当临时超出范围时,将在mat指针上发出delete []

这可能就是您遇到运行时问题的原因——mat所指向的内存已经被删除,您将再次删除它。

要解决此问题,您有两个选择:

  1. 通过引用dfs而不是通过值传递Graph,或者
  2. 修复Graph类以正确处理副本

对于项目1:

void dfs(Graph& g, int v, bool vazut[])

从而避免了临时副本的制作。


然而,对我来说,这只是一个创可贴解决方案,可以避免遇到复制错误(尽管无论如何都应该通过引用传递(。

更好的方法是使Graph类可以安全地复制,这意味着可以正确地进行复制,而不会出现您现在看到的"双重删除"错误。

要做到这一点,请添加以下功能来完成规则3,以允许正确执行复制:

#include <algorithm>
//…
Graph(const Graph& rhs) : mat(nullptr), nr_noduri(rhs.nr_noduri)
{
mat = new bool* [rhs.nr_noduri];
for (int i = 0; i < rhs.nr_noduri; i++) {
mat[i] = new bool[rhs.nr_noduri];
}
for (int i = 0; i < rhs.nr_noduri; i++) {
for (int j = 0; j < rhs.nr_noduri; j++) {
mat[i][j] = rhs.mat[i][j];
}
}
}
Graph& operator=(const Graph& rhs)
{
if ( this != &rhs )
{
Graph temp(rhs);
std::swap(temp.mat, mat);
std::swap(temp.nr_noduri, nr_noduri);
}
return *this;
}

您的类缺少用户定义的复制构造函数和赋值运算符(使用复制/交换习惯用法(。


另一个无关的问题是构建2D矩阵的方式。您使用的是最糟糕的方法之一,即分配指针,然后在循环中分配每一行。

它不仅是速度方面的瓶颈(为每一行调用分配器(,而且由于行被分配在堆的不同部分,以及堆碎片,它对缓存不友好。如果循环中对new[]的其中一个调用失败,如果不想泄漏内存,就必须回滚对new[]的所有成功调用。

有关创建二维阵列的更好方法,请参见此解决方案。