Ein neues System von Grund auf neu entwerfen. Ich werde die STL verwenden, um Listen und Karten bestimmter langlebiger Objekte zu speichern.
Frage: Sollte ich sicherstellen, dass meine Objekte Kopierkonstruktoren haben und Kopien von Objekten in meinen STL-Containern speichern, oder ist es im Allgemeinen besser, die Lebensdauer und den Umfang selbst zu verwalten und nur die Zeiger auf diese Objekte in meinen STL-Containern zu speichern?
Mir ist klar, dass die Details etwas kurz sind, aber ich suche nach der "theoretischen" besseren Antwort, wenn sie existiert, da ich weiß, dass beide Lösungen möglich sind.
Zwei sehr offensichtliche Nachteile beim Spielen mit Zeigern: 1) Ich muss die Zuordnung / Freigabe dieser Objekte in einem Bereich außerhalb der STL selbst verwalten. 2) Ich kann kein temporäres Objekt auf dem Stapel erstellen und es meinen Containern hinzufügen.
Fehlt mir noch etwas?
Antworten:
Da die Leute sich auf die Effizienz der Verwendung von Zeigern einlassen.
Wenn Sie die Verwendung eines std :: vector in Betracht ziehen und wenn nur wenige Aktualisierungen vorliegen und Sie häufig über Ihre Sammlung iterieren und es sich um einen nicht polymorphen Typ handelt, ist das Speichern von Objektkopien effizienter, da Sie eine bessere Referenzlokalität erhalten.
Otoh, wenn Aktualisierungen häufig sind, werden durch das Speichern von Zeigern die Kosten für das Kopieren / Verschieben gespart.
quelle
Das hängt wirklich von Ihrer Situation ab.
Wenn Ihre Objekte klein sind und das Kopieren des Objekts leicht ist, ist das Speichern der Daten in einem STL-Container meiner Meinung nach unkompliziert und einfacher zu verwalten, da Sie sich nicht um die Verwaltung auf Lebenszeit kümmern müssen.
Wenn Ihre Objekte groß sind und ein Standardkonstruktor keinen Sinn ergibt oder Kopien von Objekten teuer sind, ist das Speichern mit Zeigern wahrscheinlich der richtige Weg.
Wenn Sie Zeiger auf Objekte verwenden möchten, sehen Sie sich die Boost Pointer Container Library an . Diese Boost-Bibliothek umschließt alle STL-Container zur Verwendung mit dynamisch zugewiesenen Objekten.
Jeder Zeigercontainer (z. B. ptr_vector) übernimmt das Eigentum an einem Objekt, wenn es dem Container hinzugefügt wird, und verwaltet die Lebensdauer dieser Objekte für Sie. Sie können auch auf alle Elemente in einem ptr_-Container als Referenz zugreifen. Auf diese Weise können Sie Dinge wie tun
Diese Klassen umschließen die STL-Container und arbeiten mit allen STL-Algorithmen, was sehr praktisch ist.
Es gibt auch Möglichkeiten, das Eigentum an einem Zeiger im Container auf den Aufrufer zu übertragen (über die Freigabefunktion in den meisten Containern).
quelle
Wenn Sie polymporhische Objekte speichern, müssen Sie immer eine Sammlung von Basisklassenzeigern verwenden.
Das heißt, wenn Sie vorhaben, verschiedene abgeleitete Typen in Ihrer Sammlung zu speichern, müssen Sie Zeiger speichern oder sich vom Slicing Deamon fressen lassen.
quelle
Es tut uns leid, 3 Jahre nach dem Event zu springen, aber ein Warnhinweis hier ...
Bei meinem letzten großen Projekt bestand meine zentrale Datenstruktur aus einer Reihe ziemlich einfacher Objekte. Ungefähr ein Jahr nach Projektbeginn erkannte ich, dass das Objekt tatsächlich polymorph sein musste. Es dauerte einige Wochen schwieriger und unangenehmer Gehirnoperationen, um die Datenstruktur als Satz von Basisklassenzeigern zu fixieren und alle Kollateralschäden bei der Lagerung, dem Gießen usw. von Objekten zu behandeln. Ich habe ein paar Monate gebraucht, um mich davon zu überzeugen, dass der neue Code funktioniert. Dies hat mich übrigens dazu gebracht, mir Gedanken darüber zu machen, wie gut das Objektmodell von C ++ gestaltet ist.
Bei meinem aktuellen großen Projekt besteht meine zentrale Datenstruktur aus einer Reihe recht einfacher Objekte. Ungefähr ein Jahr nach Projektbeginn (was heute der Fall ist) wurde mir klar, dass das Objekt tatsächlich polymorph sein muss. Zurück zum Netz, habe diesen Thread gefunden und Nicks Link zur Boost-Zeiger-Container-Bibliothek gefunden. Genau das musste ich letztes Mal schreiben, um alles zu reparieren, also werde ich es dieses Mal versuchen.
Die Moral für mich jedenfalls: Wenn Ihre Spezifikation nicht zu 100% in Stein gemeißelt ist, suchen Sie nach Hinweisen, und Sie können sich möglicherweise später viel Arbeit sparen.
quelle
Warum nicht das Beste aus beiden Welten herausholen: Machen Sie einen Container mit intelligenten Zeigern (wie
boost::shared_ptr
oderstd::shared_ptr
). Sie müssen den Speicher nicht verwalten und müssen sich nicht mit großen Kopiervorgängen befassen.quelle
Im Allgemeinen ist das Speichern der Objekte direkt im STL-Container am besten, da es am einfachsten, effizientesten und am einfachsten für die Verwendung des Objekts ist.
Wenn Ihr Objekt selbst eine nicht kopierbare Syntax hat oder ein abstrakter Basistyp ist, müssen Sie Zeiger speichern (am einfachsten ist die Verwendung von shared_ptr).
quelle
Sie scheinen den Unterschied gut zu verstehen. Wenn die Objekte klein und leicht zu kopieren sind, speichern Sie sie auf jeden Fall.
Wenn nicht, würde ich darüber nachdenken, intelligente Zeiger (nicht auto_ptr, ein intelligenter Zeiger mit Ref-Zählung) für diejenigen zu speichern, die Sie auf dem Heap zuweisen. Wenn Sie sich für intelligente Zeiger entscheiden, können Sie natürlich keine temporären Stapel zugewiesenen Objekte speichern (wie Sie gesagt haben).
@ Torbjörn macht einen guten Punkt über das Schneiden.
quelle
one
bisanother
wird die Referenz von freigegebenone
und geändertone
.Die Verwendung von Zeigern ist effizienter, da die Container nur Zeiger anstelle vollständiger Objekte kopieren.
Hier finden Sie einige nützliche Informationen zu STL-Containern und intelligenten Zeigern:
Warum ist es falsch, std :: auto_ptr <> mit Standardcontainern zu verwenden?
quelle
Wenn auf die Objekte an anderer Stelle im Code verwiesen werden soll, speichern Sie sie in einem Vektor von boost :: shared_ptr. Dadurch wird sichergestellt, dass Zeiger auf das Objekt gültig bleiben, wenn Sie die Größe des Vektors ändern.
Dh:
Wenn sonst niemand Zeiger auf die Objekte speichert oder die Liste nicht wächst und schrumpft, speichern Sie sie einfach als einfache alte Objekte:
quelle
Diese Frage nervt mich schon eine Weile.
Ich möchte Zeiger speichern, habe aber einige zusätzliche Anforderungen (SWIG lua-Wrapper), die möglicherweise nicht für Sie gelten.
Der wichtigste Punkt in diesem Beitrag ist, ihn selbst mit Ihren Objekten zu testen
Ich habe dies heute getan, um die Geschwindigkeit des Aufrufs einer Mitgliedsfunktion für eine Sammlung von 10 Millionen Objekten 500 Mal zu testen.
Die Funktion aktualisiert x und y basierend auf xdir und ydir (alle Float-Member-Variablen).
Ich habe eine std :: list verwendet, um beide Objekttypen zu speichern, und festgestellt, dass das Speichern des Objekts in der Liste etwas schneller ist als die Verwendung eines Zeigers. Auf der anderen Seite war die Leistung sehr ähnlich, sodass es darauf ankommt, wie sie in Ihrer Anwendung verwendet werden.
Als Referenz haben die Zeiger mit -O3 auf meiner Hardware 41 Sekunden und die Rohobjekte 30 Sekunden gedauert.
quelle