STL-List Struktur Zeiger zu halten
-
23-08-2019 - |
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);
}
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.