STL List用于保存结构指针

时间:2009-07-06 04:59:45

标签: c++ list stl pointers segmentation-fault

我有一个名为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 个答案:

答案 0 :(得分:10)

这里有几个问题。

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

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

这样做,您的代码就可以了。但是你的代码是以糟糕的方式完成的。

为什么要从堆中分配列表?看看你的代码:你有内存泄漏。您没有在任何地方致电delete r_list。这就是为什么你应该使用智能指针(std::unique_ptrstd::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通常仅在处理指针时使用。由于distanceparent不是指针,因此请使用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 };

希望这些帮助!

答案 1 :(得分:2)

首先,您没有将it初始化为任何内容。你的意思是:

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

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

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

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

另外,正如Peter指出的那样,为什么不使用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);
}

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

您尚未初始化it,因此您要插入随机/未初始化的位置/指针。

std::list添加项目的常规方式包括其方法push_backpush_front;您通常只有在之前以其他方式确定了要插入一个项目的特定位置时才使用insert