4

私は頂点と呼ばれる構造を持っており、それらへのポインタをいくつか作成しました。私がやりたいのは、それらのポインターをリストに追加することです。以下の私のコードは、ポインタをリストに挿入しようとすると、セグメンテーション違反を引き起こします。誰かが何が起こっているのか説明してもらえますか?

#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どこにも電話をかけていません。これが、スマートポインタを使用する必要がある理由です(C ++ 11を使用している場合は、同等のものをブーストしますstd::unique_ptr:および)std::shared_ptrboost::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.

1つの解決策は、ヒープに割り当てられた頂点へのポインタを格納することです。

// 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 PointerContainerLibraryを使用することで支援されます。

ただし、最良の方法は、頂点自体を(それらへのポインタではなく)格納することです。

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

これらの助けを願っています!

于 2009-07-06T05:25:16.900 に答える
2

まず第一に、あなたはit何にも初期化していない。意味は:

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

また、なぜintとcharをNULLに初期化するのですか?通常、人々はポインタにNULLを使用します。

また、列挙型をintとして使用するのではなく、列挙型に名前を付けて、列挙型の型安全性の恩恵を受けるのはどうですか?

また、頂点へのポインタを作成するために新しい変数を作成する必要はありません。挿入を呼び出すと、を渡すことができます&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ため、ランダム/初期化されていない場所/ポインタに挿入しています。

アイテムをに追加する通常の方法にはstd::list、そのメソッドpush_backpush_front;が含まれます。通常はinsert、もう1つのアイテムを挿入する特定の場所を以前に決定した場合にのみ使用します。

于 2009-07-06T05:03:06.727 に答える