【问题标题】:STL List to hold structure pointers保存结构指针的 STL 列表
【发布时间】:2010-11-08 07:13:22
【问题描述】:

我有一个名为 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);
}

【问题讨论】:

  • 您在主函数中缺少返回值

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


【解决方案1】:

这里有几个问题。

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

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 };

希望这些帮助!

【讨论】:

  • 所有细节的完美汇编。我很高兴您强调了指针的生命周期以及在堆栈和堆上分配的区别。
【解决方案2】:

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

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

【讨论】:

  • 当我尝试使用 push_back() 时,mingw 编译器给出了这个错误错误:没有匹配函数调用 `std::list >:: push_back(顶点&)'|但是,当我用 g++ 编译它时,它并没有给我那个错误。无论如何,我认为这个主题属于另一个线程。
  • 那个编译器错误看起来你可能试图将一个顶点而不是一个顶点*传递给 push_back 方法。但我可能是错的......
  • 没错,汤姆。谢谢。我需要更好地阅读错误消息
  • 哈,这需要时间,但你会做得更好。当你看到像“std::allocator”等等长的东西时不要害怕(很多时候你会得到更长的东西)。过滤掉垃圾并找到它的实质:你有一个 list 和 push_back 的 arg 说 vertex&。 :-)。
【解决方案3】:

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

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

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

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

此外,无需创建新变量来创建指向顶点的指针。调用insert时,可以传入&amp;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);
}

【讨论】:

    【解决方案4】:

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

    std::list 添加项目的正常方法包括其方法push_backpush_front;仅当您之前已确定要在其中再插入一项的特定位置时,通常才会使用 insert

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-06-28
      • 2017-11-17
      • 2020-11-19
      • 2010-09-23
      • 1970-01-01
      相关资源
      最近更新 更多