4

我有一个名为 vertex 的结构,并创建了一些指向它们的指针。我想要做的是将这些指针添加到列表中。我下面的代码在尝试将指针插入列表时会产生分段错误。有人可以解释发生了什么吗?

#include <iostream>
#include <list>

#define NUM_VERTICES 8

using namespace std;

enum { WHITE, GRAY, BLACK };

struct vertex
{
    int color;
    int distance;
    char parent;
};

int main()
{
    //create the vertices
    vertex r = {WHITE, NULL, NULL};

    //create pointer to the vertex structures
    vertex *pr = &r;

    //create a list to hold the vertices
    list<vertex*> *r_list = new list<vertex*>;

    list<vertex*>::iterator it;

    r_list->insert(it, pr);
}
4

4 回答 4

10

这里有几件事是错误的。

首先,您没有像其他人所说的那样初始化迭代器:

list<vertex*>::iterator it = r_list->begin();

这样做,你的代码会很好。但是您的代码以一种糟糕的方式完成。

为什么要从堆中分配列表?查看您的代码:您有内存泄漏。你没有delete r_list在任何地方打电话。这就是为什么你应该使用智能指针(std::unique_ptr如果std::shared_ptr你有 C++11,则提升等价物:boost::scoped_ptrboost::shared_ptr

但更好的是,只需在堆栈上执行:

//create a list to hold the vertices
list<vertex*> r_list;

list<vertex*>::iterator it = r_list->begin();

r_list.insert(it, pr);

此外,使用迭代器进行插入还有很长的路要走。只需使用push front()push back()

//create a list to hold the vertices
list<vertex*> r_list;

r_list.push_back(pr);

另一件事:如果您的列表超过了您构建的顶点,它将指向无效的东西。

例如:

// global
list<vertex*> r_list;

void some_function(void)
{
    //create the vertices
    vertex r = {WHITE, NULL, NULL};

    //create pointer to the vertex structures
    vertex *pr = &r;

    r_list.push_back(pr);
} // right here, vertex r stops existing: the list now contains an
  // invalid pointer.

一种解决方案是存储指向堆分配顶点的指针:

// global
list<vertex*> r_list;

void some_function(void)
{
    //create the vertices
    vertex *r = new vertex;
    r->color = WHITE;
    r->distance = 0;
    r->parent = 0;

    r_list.push_back(r);
}

现在,即使在函数之后,列表也指向一个有效的堆分配顶点。现在的问题是,当您使用完列表后,您需要通过 lsit 并调用delete每个元素。使用Boost Pointer Container Library可以解决这个问题。

但是,最好的方法是只存储顶点本身(而不是指向它们的指针):

//create a list to hold the vertices
list<vertex> r_list;

//create the vertices
vertex r = {WHITE, NULL, NULL};

r_list.push_back(r);

如果你给顶点一个构造函数,你甚至可以就地构造它们:

struct vertex
{
    int color;
    int distance;
    char parent;

    vertex(int _color, int _distance, char _parent) :
    color(_color),
    distance(_distance),
    parent(_parent)
    {
    }
};

//create a list to hold the vertices
list<vertex> r_list;

r_list.push_back(vertex(WHITE, NULL, NULL));

(这些现在不在您的问题范围内)

首先,NULL 通常只在处理指针时使用。因为distanceandparent不是指针,所以用它0来初始化它们,而不是NULL

//create the vertices
vertex r = {WHITE, 0, 0};

其次,使用constants而不是#define

#define NUM_VERTICES 8 // <- bad
const int NumberVertices = 8; // <- good

最后,给你的枚举一个名字,或者把它放在一个命名空间中:

enum Color { WHITE, GRAY, BLACK };

希望这些帮助!

于 2009-07-06T05:25:16.900 回答
2

首先,你没有初始化it任何东西。你的意思是:

list<vertex*>::iterator it = r_list->begin();

另外,为什么要将 int 和 char 初始化为 NULL?通常人们使用 NULL 作为指针。

另外,如何命名您的枚举并从枚举的类型安全中受益,而不是将它们用作整数?

此外,无需创建新变量来创建指向顶点的指针。当你调用 insert 时,你可以传入&r.

另外,正如彼得指出的那样,为什么不直接使用push_back()

您的代码应该看起来更像这样:


using namespace std;

enum Color { 
    WHITE, 
    GRAY, 
    BLACK 
};

struct vertex
{
    Color color;
    int distance;
    char parent;
};

int main(int argc, char** argv) {
    //create the vertices
    vertex r = {WHITE, 0, ''};

    //create a list to hold the vertices
    list* r_list = new list();

    list::iterator it = r_list->begin();
    r_list->insert(it, &r);

    // Or even better, use push_back (or front)
    r_list->push_back(&r);
}
于 2009-07-06T05:04:56.410 回答
2

您尚未初始化迭代器,因此插入无效。例如,您可以改用r_list->push_back(pr)

此外,一旦 r 超出范围,列表中的指针将无效。显然,在这种情况下这不是问题,因为它在 中main(),但我认为这不是您要使用代码的确切示例,所以它可能会回来咬你......

于 2009-07-06T05:07:40.337 回答
1

你还没有初始化it,所以你在一个随机/未初始化的地方/指针插入。

向 a 添加项目的常规std::list方法包括其方法push_backpush_front; 通常,insert只有在您之前已经确定了要再插入一个项目的特定位置时,您才会使用它。

于 2009-07-06T05:03:06.727 回答