dynamisch Objekte erstellen
-
Hi zusammen,
ich habe wieder eine Frage:
wenn ich in meinem Code dynamisch Objekte vom Typ Node erstelle, dann mache ich dies wie folgt:
Node *newNode = new Node();Innerhalb vom Typ Node sind nun wiederum andere Objekte enthalten zb.:
Node.cpp:
Node::Node(...) { // ID von Node m_id_int = nodepool.getNextFreeNode(); // double m_error_dbl = 0.0; //boolean m_nodeExists_bl = true; // Initialize Positions of Array std::vector<double> m_position_dblvec; for(int i = 0; i < m_dimOfInpData_int; ++i) { m_position_dblvec.push_back(createHazardValues()); } }Node.h:
class Node { private: int m_id_int; // ID von Node bool m_nodeExists_bl; double m_error_dbl; std::vector<double> m_position_dblvec; public: const std::vector<double>& getPositionOfNode(void); }Nun meine Frage:
Sind diese in dem Node-Objekt enthaltenen werde solange vorhanden, wie das Objekt von Node existiert?
Am Beispiel vonstd::vector<double> m_position_dblvec;.
Kann ich diesen hier so initialisieren, oder muss dieser hier sostd::vector<double> *m_position_dblvec = new std::vector<double>();initialisiert werden?
Wenn ich auf die verschiedenen Objekte INNERHALB von Node zugreife, lasse ich mir dann jedes mal einen Pointer auf das Objekt zurückgeben (also bis auf bei int, double, bool) oder gebe ich eine Referenz zurück?
Bisher habe ich es wie oben dargestellt implementiert. Nun stosse ich aber auf das Problem, dass meine Nodes die später initialisiert werden plötzlich keine Position mehr besitzten. Ihr Array mit der Position ist leer.
Dabei lasse ich mir immer eine Referenz auf den Array vom jeweiligem Node Objekt zurückgeben.
-
Wenn du dein Objekt mit new erzeugst und den vector wie im ersten Beispiel deklarierst, dann sollte er auch erhalten bleiben. Dein Problem liegt vermutlich woanders. Setze dir doch einen Breakpoint an der Stelle, an der du den vector füllst. Ich schätze mal, der wird bei den problematischen, späteren Instanzen gar nicht angesprungen.
-
redbomber schrieb:
...
Das Problem bei Vektoren ist, dass sie sich im Speicher verschieben können, wenn sie wachsen. Wenn der aktuelle Wert von
std::vector<T>::capacity()überschritten wird, dann wird der Vektor an einer anderen Stelle im Speicher neu angelegt (mit größerer Kapaziät), und der gesamte Inhalt kopiert.Zeigervariablen die Zeiger auf Objekte im Vektor halten, zeigen danach auf ungültige Speicherbereiche. Das gilt auch für Iteratoren.
Wenn Du das nicht willst, solltest Du besser
std::listbenutzen. Dort ist sichergestellte, dass Zeiger/Iteratoren gültig bleiben, solange ein Objekt nicht aus der Liste gelöscht wird.
-
Und wenn die Größe nur einmal geändert wird (bei der Erstellung zum Beispiel zig Objekte abgelegt aber nie wieder gelöscht werden), dann vorher mit vec.reserve(x) genügend Platz reservieren, dann wird auch nichts verschoben.
-
super vielen Dank schon einmal.
Der Fehler lag wie du gesagt hast an einer anderen Stelle.
(Habe den Vektor mittels Indexzugriff beschrieben, ohne ihn vorher mitvector.push_back()zu befüllen...dämlicher Fehler ;))
Aber dazu noch eine Frage:
Wenn ich auf ein Objekt nennen wir es NodePool zugreife.
Dieses Objekt besitzt einen Vektor.
Ich habe eine Methode definiert mit der ich eine Referenz zu diesem Vektor erhalte, also etwa so:const std::vector<Node*>& NodePool::getNodelist(void) { // std::vector<Node*> return nodelist; }Möchte ich nun auf von meinem Programm aus auf diesen Vektor zugreifen, mache ich folgendes:
std::vector<Node*> nodelist = nodepool.getNodelist();Wenn ich nun dieser nodelist neue Objekte vom Typ Node hinzufüge und danach teste ob dieser in der nodelist vorhanden sind, dann bemerke ich dass diese zwar in der nodelist eingefügt wurden, aber die Änderung kann ich in dem Vektor erst feststellen, wenn ich erneut:
nodelist = nodepool.getNodelist();ausführe.
Mache ich dies nicht, bekomme ich von der Veränderung nichts mit.
Aber ich dachte ich habe mitnodepool.getNodelist()eine referenz zu diesem Vektor, also keine Kopie, dann müsste ich die Änderung doch mitbekommen.
Oder liegt auch hier der Fehler irgendwo anders?
-
std::vector<Node*> nodelist = nodepool.getNodelist();Bei der Zuweisung wird die Referenz kopiert, also ein neues Objekt erzeugt.
Vielleicht so?
[cpp]std::vector<Node*>& nodelist = nodepool.getNodelist();[/cpp]
-
zuweisung schrieb:
Bei der Zuweisung wird die Referenz kopiert, also ein neues Objekt erzeugt.
Du meinst, bei der Initialisierung.
zuweisung schrieb:
Vielleicht so?
std::vector<Node*>& nodelist = nodepool.getNodelist();Das wird Probleme geben, da
getNodelist()eine Const-Referenz zurückgibt.redbomber, du hast mehrere Möglichkeiten:
- Entweder du gibst eine Referenz auf den Vector zurück, damit er von aussen verändert werden kann. Das ist aber nicht gerade schön und widerspricht dem Kapselungsprinzip.
- Du übergibst nur eine Const-Referenz, sodass man das Objekt von aussen nicht ändern kann. Die Kapselung wird immer noch nicht voll eingehalten (man hat vollen Lesezugriff, obwohl man womöglich nur ein Element braucht).
- Du überlegst dir, welche Operationen von aussen auf den Vector möglich sein sollen und bietest nur entsprechende Methoden in der Klasse an. Wenn du beispielsweise nur Elemente hinzufügen möchtest, solltest du auch nur diese Funktionalität anbieten.
- Wenn du zum Schluss kommst, dass du mehr oder weniger alle Funktionen eines
std::vectors von aussen benötigts, wäre eventuell eine vollständige Wrapperklasse angebracht.
Zugriffe auf Container innerhalb einer Klasse ist ein Designproblem, für das es nicht immer eine befriedigende Lösung gibt. Gerade erst wurde die Thematik besprochen, siehe hier.
Was die Container mit Zeigern als Elementen betrifft: Boost.Pointer Container bietet da fertige Möglichkeiten an, deren Betrachtung sich lohnen könnte.
-
Fortsetzung...
redbomber schrieb:
Was bringt mir denn dann die Referenz?
Ich dachte dies ist ein Verweis auf die Speicherstellen auf der die Objekte liegen. Dann müsste ich doch auch die Änderungen an dem Vektor mitbekommen?Diesen Schluss kann ich jetzt nicht ganz nachvollziehen. Eine Referenz bedeutet nur, dass du darauf zugreifen kannst. Änderungen am Vector bekommst du also nicht wirklich mit (wenn du nicht explizit prüfst).
Oder hab ich dich falsch verstanden?
-
doch du hast mich schon richtig verstanden.
Ich dachte mit der Referenz umgehe ich, eine Kopie von einem Objekt zu machen, indem ich sozusagen verweise auf die physikalische Stelle im Speicher habe.
Wenn ich also diese Verweise habe, dann sollte ich doch auch die Änderungen mitbekommen, welche an der Stelle im speicher vorgenommen werden.
-
redbomber schrieb:
Ich dachte mit der Referenz umgehe ich, eine Kopie von einem Objekt zu machen, indem ich sozusagen verweise auf die physikalische Stelle im Speicher habe.
Ja, das stimmt schon.
redbomber schrieb:
Wenn ich also diese Verweise habe, dann sollte ich doch auch die Änderungen mitbekommen, welche an der Stelle im speicher vorgenommen werden.
Eben, so gesehen erfährst du schon von den Änderungen (das meinte ich auch mit explizit prüfen). Aber halt nicht automatisch. Du musst schon den Zustand vorher speichern und den aktuellen mit dem vorherigen vergleichen, um festzustellen, dass was geändert wurde.
Wenn du hingegen den Container wrappen würdest (d.h. eine Klasse darum herum bauen, die ähnliche Funktionen anbietet und indirekt auf den internen Container zugreift), könntest du in den Memberfunktionen jeden Zugriff mitverfolgen. Bei einem Lesezugriff erfährst du sowieso nur auf die Art etwas.
Zusätzlich kannst du noch nebenbei auf die Methodenaufrufe reagieren, beispielsweise Anzahl Zugriffe zählen oder irgendwas.