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,可能會有意想不到收穫。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章