2016-04-18 105 views
0

認識指針分配當我嘗試調用指針上刪除對一個struct Vertex(與Vertex * v = new Vertex分配,然後成功地使用並存儲在std::list在我的類的析構,我得到這個運行時錯誤:刪除不從列表

graphtake3(12325,0x100082000) malloc: *** error for object 0x100200340: pointer being freed was not allocated 
*** 

指針肯定被分配,因爲應用程序運行良好,並且所有內容都顯示爲它應該在堆棧跟蹤中,但由於某種原因,delete似乎無法解除其分配。這裏發生了什麼,以及爲什麼不刪除工作?

這裏是相關的縮寫代碼:

#include <vector> 
#include <list> 
#include <iostream> 
#include <string> 

enum Color {BLACK, GREY, WHITE}; 

struct Vertex { 
    int id; 
    std::string name; 
    Color color; 

    Vertex(); 
    Vertex(std::string name); 

    ~Vertex(); 

}; 
class Graph { 
    std::vector<std::list<Vertex *>> adjList; 

public: 
    Graph(); 
    Graph (int nodeCount); 

    ~Graph(); 

    int newVertex(); 
    int newVertex(std::string name); 
    void newUnDirectedEdge(int v1, int v2); 
    void newDirectedEdge(int v1, int v2); 
    std::list<Vertex*> getConnections(int v); 

    friend std::ostream& operator<<(std::ostream& os, const Graph& g); 



}; 

#include "Graph.hpp" 

Vertex::Vertex() { 
    color = WHITE; 
} 

Vertex::Vertex(std::string name) { 
    this->name = name; 
    color = WHITE; 
} 

Vertex::~Vertex() { 

} 

Graph::Graph() { 

} 

Graph::Graph(int nodeCount) { 
    adjList.reserve(nodeCount); 
} 

Graph::~Graph(){ 
    for (int i = 0; i<adjList.size(); i++) { 

     for (std::list<Vertex*>::iterator iterator = adjList[i].begin(), end = adjList[i].end(); iterator !=end; iterator++) { 
      delete (*iterator); //fails 
     } 
    } 
} 

int Graph::newVertex() { 
    Vertex * v = new Vertex(); 
    adjList.push_back(std::list<Vertex *>(1, v)); 
    v->id= (int)adjList.size()-1; 
    return v->id; 
} 

int Graph::newVertex(std::string name) { 
    Vertex * v = new Vertex(); 
    adjList.push_back(std::list<Vertex *>(1, v)); 
    v->id= (int)adjList.size()-1; 
    v->name= name; 
    return v->id; 
} 

void Graph::newUnDirectedEdge(int v1, int v2) { 
    newDirectedEdge(v1, v2); 
    newDirectedEdge(v2, v1); 
} 

void Graph::newDirectedEdge(int v1, int v2) { 
    Vertex * vertex2 = adjList[v2].front(); 
    adjList[v1].push_back(vertex2); 

} 
std::list<Vertex*> Graph::getConnections(int v) { 
    return adjList[v]; 
} 

std::ostream& operator<<(std::ostream& os, const Graph& g) { 
    for (int i = 0; i<g.adjList.size(); i++) { 
     for (std::list<Vertex*>::const_iterator iterator = g.adjList[i].begin(), end = g.adjList[i].end(); iterator !=end; iterator++) { 
      os << (*iterator)->id << " (" << (*iterator)->name << ") "; 
     } 
     os << '\n'; 
    } 

    return os; 
} 

與主:

#include <iostream> 
#include "Graph.hpp" 


int main(int argc, const char * argv[]) { 
    Graph graph(5); 

    int v1 = graph.newVertex("Paris"); 
    int v2 = graph.newVertex("London"); 
    int v3 = graph.newVertex("Lyon"); 
    int v4 = graph.newVertex("Nice"); 
    int v5 = graph.newVertex("Marseille"); 
    int v6 = graph.newVertex("La Rochelle"); 
    int v7 = graph.newVertex("Toulon"); 

    graph.newUnDirectedEdge(v2, v1); 
    graph.newUnDirectedEdge(v1, v3); 
    graph.newUnDirectedEdge(v1, v4); 
    graph.newUnDirectedEdge(v3, v4); 
    graph.newUnDirectedEdge(v5, v4); 
    graph.newUnDirectedEdge(v7, v5); 

    std::cout << graph; 


    return 0; 
} 
+0

請發佈一個最小的但* *完整的**演示,讀者可以嘗試。這聽起來像是一個3規則問題。但如果沒有代碼,就不可能說出來。 –

+0

@ Cheersandhth.-Alf Ok,我添加了更完整的實現 – TheInnerParty

+0

感謝您的更新,Btw。將'Graph(const Graph&)= delete;'(假設你正在使用C++ 11)添加到'Graph'類decl中。如果你的代碼編譯在各個地方開始嘔吐,你肯定會違反[三規則](https://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming))。 – WhozCraig

回答

3

這樣做的那一刻,你都設置了災難:

void Graph::newDirectedEdge(int v1, int v2) { 
    Vertex * vertex2 = adjList[v2].front(); 
    adjList[v1].push_back(vertex2); 
} 

的問題是,你沒有辨別誰擁有一個指針。在這種情況下,您只需將指針複製到列表中。但是當您到達~Graph時,您將在列表中刪除全部指針。其中一些是通過new獲得的,有些是通過上述功能複製的。

所以錯誤是正確的:指針沒有分配。發生了什麼事,你已經刪除了它,然後你刪除了它的一個副本。

您需要重新考慮您的設計並考慮指針的所有權。或者,您可以使用大錘方法將所有內容轉換爲std::shared_ptr。但我不會推薦這個。

圖形的一種常見方法是存儲所有頂點(在std::vector中),然後按照以前的方式在單獨的結構中進行連接。然後在析構函數中,您只需翻閱矢量。你甚至可以把這作爲一個機會學習如何使用std::unique_ptr。 =)

+0

你說得對,我沒有意識到這一點。這被認爲是一個好的解決方案:當做刪除時,檢查指針是否爲空,否則調用'delete'並將指針設置爲空? – TheInnerParty

+0

不,「delete」對空指針沒有影響。問題是你有一個指針的兩個副本,你試圖刪除它們兩個。刪除一個不會奇蹟般地將另一個的值更改爲null。 – paddy

+0

將指針設置爲null不會使您免於出現此錯誤。複製的指針仍然保持不變,刪除仍然失敗。 –

0

問題是否在newDirectedEdge函數中發生? 在它的實現中,它再次複製指針和插入列表,然後兩個指針在列表中的一個地址,刪除第一次就OK了,第二次...崩潰...