c++は、ダブルフリーまたは破損(fasttop)が表示されます。
今日、グラフに関連するプログラムを書いていて、タイトルのように書いていて困ったことがありました。
1. 質問コード
ここでの目的は、主に隣接行列を使ったグラフの作成で、主なコードは主にこのブログを参考にしています。 C++】グラフの定義と性質
#include
#include
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::concreteGraph(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.concreteGraph ( 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. 解決する
まずは問題をググって、これらの問題のおおよその解決策をネットに掲載します。
- ダブルフリーまたはコラプション(fasttop)
- C++ポインタ "エラー: ダブルフリーまたは破損(out)"。
- メモリ例外解放の問題(二重解放と間違った解放)を見つけるためにvalgrindを使用した例
この出力欄を見て、結果が正しいことがわかり、ポインタを使ったと推測され、その後に続く
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回実行されました。なぜ?続けてください。
理由をググっています デストラクタが2回実行される と、本当に関連する質問を与えてくれました なぜデストラクタが2回呼ばれるのですか? すごい!驚いたことに、同じ答えがこのブログで紹介されています。
<ブロッククオートこれは、システムがデフォルトのコピーコンストラクタを呼び出した結果であることが判明しています。オブジェクトを返すときや引数を値で渡すときに、一時的なオブジェクトが生成され、その一時的なオブジェクトを生成するためにデフォルトのコピー・コンストラクタが呼び出されるのです。この例で、Effective C++の理解が深まりました。クラス内にポインタ変数がある限り、コピーコンストラクタや代入関数は自分で書かなければならないが、それらが必要ないことが確認できたら、実装せずにプライベート宣言することで、誰かが呼び出すのを防ぎ、コンパイラが生成するのを防ぐことができるのである。
この文章を読んだとき、何が書いてあるのか最初は少し混乱し、仕方なくC++ Primerを出してきてパラパラと読んでみました:the
ここで注目の言葉
デフォルトのコピーコンストラクタは、返されたオブジェクトに値で引数が渡されたときに呼び出されます!
そこで、コピーされないようにするための機能表示を、そのまま、クラスに ブロックコピー と ブロックアサイン
AdjGraph(const AdjGraph&) = delete;
AdjGraph &operator=(const AdjGraph&) = delete;
そして、コードを実行すると、次のようになります。
削除された機能を使用するものは、よく
ブロックコピー
削除された機能を使ってみよう~~~ちょっと待てよ、急に気がついたことがあるんだが、そういえば
printGraph
フォームパラメータは値として渡されたので、前の文はシステムのデフォルトを呼び出したことになる
コピーコンストラクタ
で、プログラムの最後に、2番目の
デストラクタ
というように、2番目の
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
のように、値の代わりに参照が渡され、デフォルトのコピーコンストラクタは呼ばれず、デストラクトが1回だけ発生するようにします。ブロッキングコピーとブロッキング代入については、削除しても残しても今のところプログラムにはほとんど影響がありません。
#include
#include
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::concreteGraph(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) {
まあ、それでも問題にぶつかったらもっと考えてググる必要があるし、思わぬ結果が出るかもしれない。
関連
-
エラー: 'xxx' は事前宣言と C++ ヘッダーファイルが互いに含まれているため、型名になりません。
-
C++コンパイルエラー:||error: ld returned 1 exit status|.
-
C/C++共通エラーの概要
-
c++11の機能を含むcmakeの書き方 (-std=c++11 cmakeList.txtに書き込む方法)
-
警告 - 符号付き整数式と符号なし整数式の比較 [-Wsign-compare] 解決方法
-
一意でないテーブル/エイリアス
-
c++ 11 random ライブラリの簡単な使い方
-
C++テンプレートテンプレート使用法まとめ
-
C++エラー:不明な型名
-
ベクトル添え字が範囲外のコンテナの使用、その他類似のエラー
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
c++ プログラミング プロンプトの関数定義はここでは許可されません。
-
C++11での移動セマンティクス(std::move)と完全な前進(std::forward)。
-
undefinederror: 'dynamic_cast' の前に unqualified-id を指定する必要があります。
-
C++:ソースファイルを開くことができない問題
-
C++のostreamの詳細な使用方法
-
C++-コラムフィッティングフィットシリンダー
-
不完全なクラス型へのポインタが許可されていないのですが、どのようなエラーですか?
-
const char*' から `char*' への変換が無効な場合の対処法
-
C/C++ におけるランダム関数 rand() および srand() の使用法
-
c/c++の "undefined reference to "の解決法