Frage

Ich habe eine Struktur namens Vertex und ich geschaffen, um ihnen einige Hinweise. Was ich tun möchte, ist diese Zeiger zu einer Liste hinzuzufügen. Mein Code unten, wenn er versucht, den Zeiger in die Liste einzufügen, erzeugt einen Segmentation Fault. Kann jemand bitte erklären, was los ist?

#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);
}
War es hilfreich?

Lösung

Es gibt mehrere Dinge falsch hier.

Zunächst einmal, Sie initialisieren nicht den Iterator, wie andere gesagt hat:

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

Tun Sie dies und Ihr Code wird gut. Aber Ihr Code in einer schlechten Art und Weise.

Warum Zuweisung Sie die Liste aus dem Heap? Schauen Sie sich Ihr Code: Sie einen Speicherverlust haben. Sie rufen nicht delete r_list überall. Aus diesem Grund sollten Sie intelligente Zeiger verwenden ( std::unique_ptr , std::shared_ptr wenn Sie C ++ 11, Boost-Äquivalente anders: boost::scoped_ptr und boost::shared_ptr )

Aber noch besser, tun Sie es einfach auf dem Stack:

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

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

r_list.insert(it, pr);

Darüber hinaus dem Iterator einfügen wird über die Dinge gehen den langen Weg. Verwenden Sie einfach Push-Front () oder zurückzudrängen () :

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

r_list.push_back(pr);

Eine andere Sache. Wenn Sie Ihre Liste der Vertex überlebt Sie aufgebaut haben, wird es etwas ungültig Hinweis auf sein

Zum Beispiel:

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

Eine Lösung ist, zu speichern Zeiger auf dem Heap zugewiesen Eckpunkten:

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

Jetzt auch nach der Funktion in der Liste auf einen gültigen Heap zugeordnet Vertex zeigt wird. Dies hat nun das Problem, dass, wenn Sie die Liste fertig sind verwenden, müssen Sie die lsit gehen und rufen delete auf jedem Element. Dieses Problem wird unterstützt durch die Pointer Container-Bibliothek Erhöhung .

Die beste Art und Weise, ist aber nur speichern Eckpunkten selbst (anstatt Zeiger auf sie):

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

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

r_list.push_back(r);

Wenn Sie Vertex einen Konstruktor geben, können Sie sogar konstruieren sie nur an Ort und Stelle:

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

(diese sind nun außerhalb Ihres Problems)

Als erstes wird NULL im Allgemeinen nur dann verwendet, wenn sie mit Zeigern zu tun. Da distance und parent keine Zeiger sind, verwenden 0 sie zu initialisieren, anstatt NULL:

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

Zweitens Verwendung constants statt #define:

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

Schließlich geben Sie Ihre ENUM einen Namen, oder legen Sie sie in einem Namespace:

enum Color { WHITE, GRAY, BLACK };

Hoffe, dass diese Hilfe!

Andere Tipps

Sie haben den Iterator nicht initialisiert, so ist es nicht gültig einfügen mit. Sie könnten r_list->push_back(pr) stattdessen beispielsweise verwenden.

Auch werden die Zeiger in der Liste nicht sein gültig, wenn r den Gültigkeitsbereich verlässt. Offensichtlich ist das kein Problem in diesem Fall, da es in main(), aber ich nehme an, dies ist nicht das genaue Beispiel ist, wo Sie gehen, den Code zu verwenden, so kann es kommen, wie sie zu beißen ...

Zu allererst Sie initialisieren nicht it zu nichts. Meinen Sie:

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

Auch, warum Sie ein int und char zu initialisieren NULL? Normalerweise Menschen NULL verwenden für Zeiger.

Auch, wie über Ihre Enum und profitieren von der Typsicherheit von Aufzählungen zu nennen, statt mit ihnen als Ints?

Auch keine Notwendigkeit, eine neue Variable erstellen einen Zeiger auf den Scheitelpunkt zu machen. Wenn Sie Insert aufrufen, können Sie in &r passieren.

Auch als Peter darlegt, warum nicht nur push_back() benutzen?

Der Code sollte mehr wie folgt aussehen:


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

Sie haben it nicht initialisiert, so dass Sie bei einem zufälligen / uninitialized Ort / Zeiger sind eingefügt wird.

Normale Weisen von Elementen zu einem std::list Zugabe sind seine Methoden push_back und push_front; Sie würden normalerweise nur verwenden insert, wenn Sie zuvor sonst hatte die bestimmte Stelle bestimmt, in dem Sie ein weiteres Element eingefügt werden soll.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top