it-swarm.com.de

Soll ich ganze Objekte oder Zeiger auf Objekte in Containern speichern?

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 über Kopierkonstruktoren verfügen und Kopien von Objekten in meinen STL-Containern speichern, oder ist es im Allgemeinen besser, das Leben und den Umfang selbst zu verwalten und 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 es sie gibt, da ich weiß, dass beide Lösungen möglich sind.

Zwei offensichtliche Nachteile beim Spielen mit Zeigern: 1) Ich muss die Zuordnung/Freigabe dieser Objekte selbst in einem Bereich außerhalb der AWL verwalten. 2) Ich kann kein temporäres Objekt auf dem Stapel erstellen und es meinen Containern hinzufügen.

Fehlt mir noch etwas?

160
Stéphane

Da sich die Leute auf die Effizienz der Verwendung von Zeigern einlassen.

Wenn Sie die Verwendung eines std :: vector in Betracht ziehen und wenn nur wenige Aktualisierungen vorhanden sind und Sie häufig über Ihre Sammlung iterieren und es sich um einen nicht polymorphen Typ handelt, ist das Speichern von Objekt- "Kopien" effizienter, da Sie eine bessere Referenzlokalität erhalten.

Wenn Aktualisierungen häufig verwendet werden, werden durch das Speichern von Zeigern die Kopier-/Umzugskosten gespart.

67

Das hängt wirklich von Ihrer Situation ab.

Wenn Ihre Objekte klein sind und das Erstellen einer Kopie des Objekts sehr einfach ist, ist das Speichern der Daten in einem STL-Container meiner Meinung nach unkompliziert und einfacher, da Sie sich nicht um die Verwaltung der Lebensdauer 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 sich für die Verwendung von Zeigern auf Objekte entscheiden, lesen Sie die Boost Pointer Container Library . Diese Boost-Bibliothek umschließt alle AWL-Container für die Verwendung mit dynamisch zugewiesenen Objekten.

Jeder Zeigercontainer (z. B. ptr_vector) übernimmt den Besitz eines Objekts, wenn es dem Container hinzugefügt wird, und verwaltet die Lebensdauer dieser Objekte für Sie. Sie können auch per Verweis auf alle Elemente in einem ptr_-Container zugreifen. Auf diese Weise können Sie Dinge wie tun

class BigExpensive { ... }

// create a pointer vector
ptr_vector<BigExpensive> bigVector;
bigVector.Push_back( new BigExpensive( "Lexus", 57700 ) );
bigVector.Push_back( new BigExpensive( "House", 15000000 );

// get a reference to the first element
MyClass& expensiveItem = bigList[0];
expensiveItem.sell();

Diese Klassen umschließen die STL-Container und arbeiten mit allen STL-Algorithmen, was sehr praktisch ist.

Es gibt auch Möglichkeiten, den Besitz eines Zeigers im Container auf den Aufrufer zu übertragen (über die Freigabefunktion in den meisten Containern).

46
Nick Haddad

Wenn Sie polymporhische Objekte speichern, müssen Sie immer eine Sammlung von Basisklassenzeigern verwenden.

Wenn Sie verschiedene abgeleitete Typen in Ihrer Sammlung speichern möchten, müssen Sie Zeiger speichern oder sich vom Slicing-Deamon verzehren lassen.

38

Tut mir leid, dass ich 3 Jahre nach dem Event einspringe, aber hier ein Hinweis ...

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, als sich die Anforderungen entwickelten. Es dauerte einige Wochen schwieriger und unangenehmer Gehirnoperationen, um die Datenstruktur in eine Reihe von Basisklassenzeigern umzuwandeln und alle Kollateralschäden bei der Objektspeicherung, beim Wirken usw. zu bewältigen. Ich habe ein paar Monate gebraucht, um mich davon zu überzeugen, dass der neue Code funktioniert. Im Übrigen hat mich das sehr nachdenklich gemacht, wie gut das Objektmodell von C++ entworfen ist.

In meinem aktuellen großen Projekt besteht meine zentrale Datenstruktur aus einer Reihe ziemlich einfacher Objekte. Ungefähr ein Jahr nach Beginn des Projekts (was heute passiert) 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. Dies ist genau das, was ich das letzte Mal schreiben musste, 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, gehen Sie auf Zeiger, und Sie können sich möglicherweise später eine Menge Arbeit sparen.

22
EML

Warum nicht das Beste aus beiden Welten holen: einen Container mit intelligenten Zeigern (wie boost::shared_ptr oder std::shared_ptr ). Sie müssen den Speicher nicht verwalten und müssen sich nicht mit umfangreichen Kopiervorgängen befassen.

19
Branan

Im Allgemeinen ist es am besten, die Objekte direkt im AWL-Container zu speichern, da dies am einfachsten und effizientesten ist und die Verwendung des Objekts am einfachsten ist.

Wenn Ihr Objekt selbst eine nicht kopierbare Syntax aufweist oder ein abstrakter Basistyp ist, müssen Sie Zeiger speichern (am einfachsten ist es, shared_ptr zu verwenden).

11
Greg Rogers

Sie scheinen den Unterschied gut zu verstehen. Wenn die Objekte klein und leicht zu kopieren sind, sollten Sie sie unbedingt aufbewahren.

Wenn nicht, würde ich darüber nachdenken, intelligente Zeiger (nicht auto_ptr, ein intelligenter Zeiger für die Referenzzä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 Objekte speichern, die einem temporären Stapel zugeordnet sind (wie Sie gesagt haben).

@ Torbjörn macht einen guten Punkt über das Schneiden.

3
Lou Franco

Die Verwendung von Zeigern ist effizienter, da die Container nur Zeiger anstelle von vollständigen Objekten 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?

3
17 of 26

Wenn die Objekte an anderer Stelle im Code referenziert werden sollen, 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:

std::vector<boost::shared_ptr<protocol> > protocols;
...
connection c(protocols[0].get()); // pointer to protocol stays valid even if resized

Wenn sonst niemand Zeiger auf die Objekte speichert oder die Liste nicht wächst und schrumpft, speichern Sie sie einfach als einfache alte Objekte:

std::vector<protocol> protocols;
connection c(protocols[0]); // value-semantics, takes a copy of the protocol
2

Diese Frage nervt mich schon eine Weile.

Ich möchte Zeiger speichern, habe jedoch einige zusätzliche Anforderungen (SWIG-Lua-Wrapper), die möglicherweise nicht für Sie zutreffen.

Der wichtigste Punkt in diesem Beitrag ist testen Sie es selbst mit Ihre Objekte

Ich habe dies heute getan, um die Geschwindigkeit des 500-maligen Aufrufs einer Member-Funktion für eine Sammlung von 10 Millionen Objekten 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 aufzunehmen, und festgestellt, dass das Speichern des Objekts in der Liste etwas schneller ist als die Verwendung eines Zeigers. Andererseits war die Leistung sehr ähnlich, sodass es darauf ankommt, wie sie in Ihrer Anwendung verwendet werden.

Zum Nachschlagen, mit -O3 auf meiner Hardware dauerten die Zeiger 41 Sekunden und die Rohobjekte 30 Sekunden.

1
Meleneth