2016-04-18 67 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了,第二次...崩溃...