C++ 保存结构指针的 STL 列表

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1085489/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 18:44:01  来源:igfitidea点击:

STL List to hold structure pointers

c++liststlpointerssegmentation-fault

提问by unknown

I have a structure called vertex and I created some pointers to them. What I want to do is add those pointers to a list. My code below, when it tries to insert the pointer into the list, creates a segmentation fault. Can someone please explain what is going on?

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

回答by GManNickG

There are several things wrong here.

这里有几件事是错误的。

First off, you aren't initializing the iterator, like other's have said:

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

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

Do this and your code will be fine. But your code is done in a bad manner.

这样做,你的代码会很好。但是你的代码做得不好。

Why are you allocating the list from the heap? Look at your code: you have a memory leak. You aren't calling delete r_listanywhere. This is why you should use smart pointers (std::unique_ptr, std::shared_ptrif you have C++11, boost equivalents otherwise : boost::scoped_ptrand boost::shared_ptr)

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

But better yet, just do it on the stack:

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

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

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

r_list.insert(it, pr);

In addition, using the iterator to insert is going about things the long way. Just use push front()or push back():

此外,使用迭代器插入是很长的路要走的事情。只需使用push front()push back()

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

r_list.push_back(pr);

Another thing: if your list outlives the vertex you've constructed, it will be pointing to something invalid.

另一件事:如果您的列表比您构建的顶点寿命长,它将指向无效的内容。

For example:

例如:

// 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.

One solution is to store pointers to heap-allocated vertices:

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

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

Now even after the function the list is pointing to a valid heap-allocated vertex. This now has the problem that when you're done using the list, you need to go through the lsit and call deleteon each element. This problem is assisted by using the Boost Pointer Container Library.

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

The best way, though, is to just store vertices themselves (rather than pointers to them):

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

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

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

r_list.push_back(r);

If you give vertex a constructor, you can even just construct them in-place:

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

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

(these are now outside your problem)

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

Firstly, NULL is generally only used when dealing with pointers. Since distanceand parentare not pointers, use 0to initialize them, rather than NULL:

首先,NULL 一般只在处理指针时使用。由于distanceparent不是指针,使用0来初始化它们,而不是NULL

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

Secondly, use constantsrather than #define:

其次,使用constants而不是#define

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

Lastly, give your enum a name, or place it in a namespace:

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

enum Color { WHITE, GRAY, BLACK };

Hope these help!

希望这些有帮助!

回答by Tom

First of all, you aren't initializing itto anything. Do you mean:

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

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

Also, why are you initializing an int and char to NULL? Usually people use NULL for pointers.

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

Also, how about naming your enum and benefiting from the type safety of enums, instead of using them as ints?

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

Also, no need to create a new variable to make a pointer to the vertex. When you call insert, you can pass in &r.

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

Also, as Peter points out, why not just use push_back()?

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

Your code should look more like this:

您的代码应该更像这样:


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

回答by Peter

You haven't initialised the iterator, so it's not valid to insert with. You could use r_list->push_back(pr)instead, for example.

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

Also, the pointers in your list aren't going to be valid once r goes out of scope. Obviously that's not a problem in this case since it's in main(), but I assume this isn't the exact example where you're going to use the code, so it may come back to bite you...

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

回答by Alex Martelli

You have not initialized it, so you're inserting at a random/uninitialized place/pointer.

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

Normal ways of adding items to a std::listinclude its methods push_backand push_front; you'd normally use insertonly if you had previously otherwise determined the specific spot in which you want to insert one more item.

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