c++出现double free or corruption (fasttop)

今天在写图的相关的程序,写着写着就出现了一个问题,如标题。

1. 问题代码

这里我们的目标主要是想要是利用邻接矩阵创建一个图,主要代码主要是参考这篇博客【C++】图的定义及性质

#include <iostream>
#include <climits>

enum GraphKind {DG, UDG, DN, UDN};
/* directed graph, undirected graph, directed netword, undirected network*/

class AdjGraph {
 public:
     int *vertex;   // vertex array
     int **matrix;  // adjoin matrix
     int vertexNum; // total vertex num
     int edgeNum;   // total edgeNum
     enum GraphKind kind;   // graph kinds
     AdjGraph(int Vertex);  // constructor
//     AdjGraph(const AdjGraph&) = delete;
//     AdjGraph &operator=(const AdjGraph&) = delete;
     ~AdjGraph();   // destructor
     void setEdge(AdjGraph& G, int start, int end); // set graph edge
     void setEdge(AdjGraph& G, int start, int end, int weight);  // set network edge
     void setEdgeNum(int EdgeNum);  // set gprah edge num
     int getEdgeNum() const; // get graph edge num
     void creteGraph(AdjGraph& G, enum GraphKind kind); // create graph/network
     void clearGraph(AdjGraph& G); // clear the graph
     void printGraph(AdjGraph G) const; // print the graph
};

AdjGraph::AdjGraph(int Vertex) {
    vertexNum = Vertex;
    edgeNum = 0;
}

AdjGraph::~AdjGraph() {
    edgeNum = 0;
    delete vertex;
    vertex = nullptr;
    for (int i = 0; i < vertexNum; ++i) {
        delete [] matrix[i];
        matrix[i] = nullptr;
    }
    delete [] matrix;
    matrix = nullptr;
    vertexNum = 0;
}

void AdjGraph::setEdge(AdjGraph& G, int start, int end) {
//    Edge e(start, end);
    if (G.kind == UDG) {
        G.matrix[start - 1][end - 1] = 1;
        G.matrix[end - 1][start - 1] = 1;
    } else if (G.kind == DG) {
        G.matrix[start - 1][end - 1] = 1;
    }
}

void AdjGraph::setEdge(AdjGraph& G, int start, int end, int weight) {
//    Edge e(start, end, weight);
    if (G.kind == UDN) {
        G.matrix[start - 1][end - 1] = weight;
        G.matrix[end - 1][start - 1] = weight;
    } else if (G.kind == DN) {
        G.matrix[start - 1][end - 1] = weight;
    }
}

void AdjGraph::setEdgeNum(int EdgeNum) {
    edgeNum = EdgeNum;
}

int AdjGraph::getEdgeNum() const {
    return edgeNum;
}

void AdjGraph::creteGraph(AdjGraph& G, enum GraphKind kind) {
    G.vertex = new int[G.vertexNum]; // create graph/network vertex
    for (int i = 0; i < vertexNum; ++i) {
        G.vertex[i] = i + 1;
    }
    G.matrix = new int*[G.vertexNum];
    for (int i = 0; i < vertexNum; ++i) {
        G.matrix[i] = new int[G.vertexNum];
    }
    G.kind = kind;  // get our kind
    for (int i = 0; i < G.vertexNum; ++i) {
        for (int j = 0; j < G.vertexNum; ++j) {
            if (G.kind == UDG || G.kind == DG) {
                G.matrix[i][j] = 0;
            } else if (G.kind == UDN || G.kind == DN) {
                G.matrix[i][j] = INT_MAX;
            } else {
                std::cout << "useless GraphKind parameters" << std::endl;
                break;
            }
        }
    }
}

void AdjGraph::clearGraph(AdjGraph& G) {
    G.edgeNum = 0;
    delete G.vertex;
    G.vertex = nullptr;
    for (int i = 0; i < G.vertexNum; ++i) {
        delete G.matrix[i];
        G.matrix[i] = nullptr;
    }
    delete G.matrix;
    G.matrix = nullptr;
    G.vertexNum = 0;
}

void AdjGraph::printGraph(AdjGraph G) const  {
    if (G.vertexNum != 0) {
        for (int i = 0; i < G.vertexNum; ++i) {
            for (int j = 0; j < G.vertexNum; ++j) {
                if (G.matrix[i][j] == INT_MAX) {
                    std::cout << "∞" << " ";
                } else {
                    std::cout << G.matrix[i][j] << " ";
                }
            }
            std::cout << "\n";
        }
    } else {
        std::cout << "graph is empty!" << std::endl;
    }
}

int main() {

	AdjGraph G1 ( 5 );
//    G1.setEdgeNum ( 6 );
	G1.creteGraph ( G1, UDG ); // undirected graph
	G1.setEdge ( G1, 1, 2 );
	G1.setEdge ( G1, 1, 4 );
	G1.setEdge ( G1, 2, 3 );
	G1.setEdge ( G1, 3, 4 );
	G1.setEdge ( G1, 3, 5 );
	G1.setEdge ( G1, 2, 5 );
	G1.printGraph ( G1 );
    return 0;
}

在这里插入图片描述
看着错误是挺吓人的,但是主要问题就是double free or corruption (fasttop)错误。

2. 解决

遇到问题我们首先是google呗,先贴一下网上的这些问题大概解决。

  1. double free or corruption (fasttop)
  2. C++ pointer “error: double free or corruption (out)”
  3. 实例介绍利用valgrind定位内存异常释放问题(double free 和wrong free)

看到这个输出栏发现结果是正确的,然后我们猜测我们使用了指针,后面又进行了delete操作,可能是析构函数有点问题。首选我们在析构函数中添加一句测试代码,变成这样:

AdjGraph::~AdjGraph() {
    edgeNum = 0;
    delete vertex;
    vertex = nullptr;
    std::cout << "hello" << std::endl;
    for (int i = 0; i < vertexNum; ++i) {
        delete [] matrix[i];
        matrix[i] = nullptr;
    }
    delete [] matrix;
    matrix = nullptr;
    vertexNum = 0;
}

然后输出这个:
在这里插入图片描述

然后我们竟然发现析构函数竟然执行了2次!why? 继续:

我们在Google一下,为什么析构函数会执行2次,结果真给我找到了相关的问题为什么会两次调用析构函数,哇!竟然如出一辙,这篇博客给出的解答是:

发现原来是系统调用默认拷贝构造函数的结果。在返回对象和按值传递参数时,要生成临时对象,生成临时对象要调用默认拷贝构造函数。通过这个例子更让我加深了对Effective C++的理解。只要类里有指针变量就得自己写拷贝构造函数和赋值函数,但是你确定用不着这些函数时,可以把这些函数做private声明而不去实现它,这就防止了会有人去调用它们,也防止了编译器去生。

一开始看这句话的时候有点懵逼,说的是啥,没办法,只能把《C++ Primer》拿出来翻一翻:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
这里的话主要重点:当返回对象是按值传递参数时候,会调用默认的拷贝构造函数!

所以了话,我们话就按照它的方法将函数显示设置为阻止拷贝,在类中添加阻止拷贝阻止赋值

     AdjGraph(const AdjGraph&) = delete;
     AdjGraph &operator=(const AdjGraph&) = delete;

然后运行代码发现:
在这里插入图片描述
什么使用了已经删除了函数,好吧,阻止拷贝让我们使用了已经删除的函数~~等一下,突然我意识到了什么,我好像printGraph形参传入的是值啊,所以之前的话会调用系统默认的拷贝构造函数,然后程序结束的时候会调用二次析构函数,这样就会二次delete指针,然后就会出现double free or corruption (fasttop)错误,好像分析的有点道理。

原来定义的printGraph函数:

void AdjGraph::printGraph(AdjGraph G) const  {
    if (G.vertexNum != 0) {
        for (int i = 0; i < G.vertexNum; ++i) {
            for (int j = 0; j < G.vertexNum; ++j) {
                if (G.matrix[i][j] == INT_MAX) {
                    std::cout << "∞" << " ";
                } else {
                    std::cout << G.matrix[i][j] << " ";
                }
            }
            std::cout << "\n";
        }
    } else {
        std::cout << "graph is empty!" << std::endl;
    }
}

既然找到了原因那我们对原来的printGraph进行修改,将其形参变成引用类型,这样就是传引用而不是值,也就不会调用系统默认的拷贝构造函数,也就只会发生一次析构了。对于阻止拷贝和阻止赋值,去掉和保留暂时对本程序影响不大。

#include <iostream>
#include <climits>

enum GraphKind {DG, UDG, DN, UDN};
/* directed graph, undirected graph, directed netword, undirected network*/

class AdjGraph {
 public:
     int *vertex;   // vertex array
     int **matrix;  // adjoin matrix
     int vertexNum; // total vertex num
     int edgeNum;   // total edgeNum
     enum GraphKind kind;   // graph kinds
     AdjGraph(int Vertex);  // constructor
     AdjGraph(const AdjGraph&) = delete;
     AdjGraph &operator=(const AdjGraph&) = delete;
     ~AdjGraph();   // destructor
     void setEdge(AdjGraph& G, int start, int end); // set graph edge
     void setEdge(AdjGraph& G, int start, int end, int weight);  // set network edge
     void setEdgeNum(int EdgeNum);  // set gprah edge num
     int getEdgeNum() const; // get graph edge num
     void creteGraph(AdjGraph& G, enum GraphKind kind); // create graph/network
     void clearGraph(AdjGraph& G); // clear the graph
     void printGraph(AdjGraph& G) const; // print the graph
};

AdjGraph::AdjGraph(int Vertex) {
    vertexNum = Vertex;
    edgeNum = 0;
}

AdjGraph::~AdjGraph() {
    edgeNum = 0;
    delete vertex;
    vertex = nullptr;
    for (int i = 0; i < vertexNum; ++i) {
        delete [] matrix[i];
        matrix[i] = nullptr;
    }
    delete [] matrix;
    matrix = nullptr;
    vertexNum = 0;
}

void AdjGraph::setEdge(AdjGraph& G, int start, int end) {
//    Edge e(start, end);
    if (G.kind == UDG) {
        G.matrix[start - 1][end - 1] = 1;
        G.matrix[end - 1][start - 1] = 1;
    } else if (G.kind == DG) {
        G.matrix[start - 1][end - 1] = 1;
    }
}

void AdjGraph::setEdge(AdjGraph& G, int start, int end, int weight) {
//    Edge e(start, end, weight);
    if (G.kind == UDN) {
        G.matrix[start - 1][end - 1] = weight;
        G.matrix[end - 1][start - 1] = weight;
    } else if (G.kind == DN) {
        G.matrix[start - 1][end - 1] = weight;
    }
}

void AdjGraph::setEdgeNum(int EdgeNum) {
    edgeNum = EdgeNum;
}

int AdjGraph::getEdgeNum() const {
    return edgeNum;
}

void AdjGraph::creteGraph(AdjGraph& G, enum GraphKind kind) {
    G.vertex = new int[G.vertexNum]; // create graph/network vertex
    for (int i = 0; i < vertexNum; ++i) {
        G.vertex[i] = i + 1;
    }
    G.matrix = new int*[G.vertexNum];
    for (int i = 0; i < vertexNum; ++i) {
        G.matrix[i] = new int[G.vertexNum];
    }
    G.kind = kind;  // get our kind
    for (int i = 0; i < G.vertexNum; ++i) {
        for (int j = 0; j < G.vertexNum; ++j) {
            if (G.kind == UDG || G.kind == DG) {
                G.matrix[i][j] = 0;
            } else if (G.kind == UDN || G.kind == DN) {
                G.matrix[i][j] = INT_MAX;
            } else {
                std::cout << "useless GraphKind parameters" << std::endl;
                break;
            }
        }
    }
}

void AdjGraph::clearGraph(AdjGraph& G) {
    G.edgeNum = 0;
    delete G.vertex;
    G.vertex = nullptr;
    for (int i = 0; i < G.vertexNum; ++i) {
        delete G.matrix[i];
        G.matrix[i] = nullptr;
    }
    delete G.matrix;
    G.matrix = nullptr;
    G.vertexNum = 0;
}

void AdjGraph::printGraph(AdjGraph& G) const  {
    if (G.vertexNum != 0) {
        for (int i = 0; i < G.vertexNum; ++i) {
            for (int j = 0; j < G.vertexNum; ++j) {
                if (G.matrix[i][j] == INT_MAX) {
                    std::cout << "∞" << " ";
                } else {
                    std::cout << G.matrix[i][j] << " ";
                }
            }
            std::cout << "\n";
        }
    } else {
        std::cout << "graph is empty!" << std::endl;
    }
}

int main() {

	AdjGraph G1 ( 5 );
//    G1.setEdgeNum ( 6 );
	G1.creteGraph ( G1, UDG ); // undirected graph
	G1.setEdge ( G1, 1, 2 );
	G1.setEdge ( G1, 1, 4 );
	G1.setEdge ( G1, 2, 3 );
	G1.setEdge ( G1, 3, 4 );
	G1.setEdge ( G1, 3, 5 );
	G1.setEdge ( G1, 2, 5 );
	G1.printGraph ( G1 );
    std::cout << std::endl;
	AdjGraph G2 ( 4 );
	G2.setEdgeNum ( 4 );
	G2.creteGraph ( G2, DG );
	G2.setEdge ( G2, 1, 2 );
	G2.setEdge ( G2, 1, 3 );
	G2.setEdge ( G2, 4, 1 );
	G2.setEdge ( G2, 3, 4 );
	G2.printGraph ( G2 );
	std::cout << std::endl;
	AdjGraph G3 ( 6 );
	G3.setEdgeNum ( 9 );
	G3.creteGraph ( G3, DN );
	G3.setEdge ( G3, 1, 2, 50 );
	G3.setEdge ( G3, 2, 3, 40 );
	G3.setEdge ( G3, 4, 3, 50 );
	G3.setEdge ( G3, 5, 4, 50 );
	G3.setEdge ( G3, 6, 5, 10 );
	G3.setEdge ( G3, 6, 1, 30 );
	G3.setEdge ( G3, 1, 4, 70 );
	G3.setEdge ( G3, 4, 6, 60 );
	G3.setEdge ( G3, 3, 6, 90 );
	G3.printGraph ( G3 );

    return 0;
}

在这里插入图片描述

好吧,遇到问题还是需要多思考,多Google,可能会有意想不到收获。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值