2010-12-29 4 views
3

Ich habe ein Projekt, und ich möchte Smart Pointer Verwendung besser machen.Smart-Zeiger Verwendung

Die Hauptidee besteht darin, sie zu verwenden, wenn ein neues Objekt von der Funktion zurückgegeben wird. Die Frage ist, was Smart Pointer zu verwenden? auto_ptr oder shared_ptr von Boost? Wie ich weiß, ist auto_ptr langsamer, aber es kann auf den "reinen" Zeiger zurückgreifen.

Und wenn ich Smart Pointer anstelle wo ich es nicht brauche, würde es die Leistung langsamer machen?

+0

Wählen Sie nicht intelligente Zeiger basierend auf wahrgenommene Effizienz (für einen Menschen sind absolut schrecklich bei der Wahrnehmung von Effizienz und wie gezeigt, in der Regel falsch). Wählen Sie den Smart-Zeiger, der zeigt, wie Sie den Zeiger erwarten. Wenn Sie Eigentumsrechte übertragen, ist auto_ptr in Ordnung, wenn Sie ein implizit gemeinsam genutztes Objekt erstellen, ist shared_ptr besser. –

Antwort

11

Vermeidung Was macht denken Sie auto_ptr als shared_ptr langsamer ist? Normalerweise würde ich das Gegenteil erwarten, da shared_ptr die Referenzzahl aktualisieren muss.

Für welche Sie verwenden sollten, verschiedene Smart Pointer implizieren unterschiedliche Besitz Semantik. Eigentum beinhaltet die Verantwortung, das Objekt zu löschen, wenn es nicht länger benötigt wird.

  • Ein Rohzeiger impliziert kein Eigentum; Ein Programm, das intelligente Zeiger richtig verwendet, kann immer noch rohe Zeiger an vielen Stellen verwenden, an denen der Besitz nicht beabsichtigt ist. Wenn Sie beispielsweise einen optionalen Verweis auf ein Objekt in eine Funktion übergeben möchten, verwenden Sie häufig einen rohen Zeiger).
  • scoped_ptr bedeutet single (dh nicht geteilt), nicht übertragbar Eigentum.
  • auto_ptr bedeutet single (dh nicht gemeinsam) übertragbar Eigentum.Dies ist der intelligente Zeiger, den ich verwenden würde, um ein neu konstruiertes Objekt von einer Funktion zurückzugeben (die Funktion ist , die das Objekt an seinen Aufrufer überträgt). auto_ptr leidet unter dem Nachteil, dass aufgrund von Einschränkungen der Sprache, wenn auto_ptr definiert wurde, es schwierig ist, richtig zu verwenden (dies hat es einen sehr schlechten Ruf gegeben, obwohl der beabsichtigte Zweck eines Smart-Pointer mit einzelnen, übertragbaren Besitz Semantik war und ist) gültig und nützlich).
  • unique_ptr hat dieselbe Semantik wie auto_ptr, verwendet aber neue C++ 0x-Funktionen (rvalue-Referenzen), um es sicherer (weniger anfällig für falsche Verwendung) als auto_ptr zu machen. Wenn Sie auf einer Plattform arbeiten, auf der unique_ptr verfügbar ist, sollten Sie sie anstelle von auto_ptr verwenden.
  • shared_ptr bedeutet geteilt Eigentum. Meiner Meinung nach wird dies zu viel genutzt. Es hat viele gültige Verwendungen, aber es sollte nicht einfach als Standardoption verwendet werden.

würde ich auch hinzufügen, dass shared_ptr oft mit STL-Containern verwendet wird, weil die anderen Smart-Pointer-Klassen ihre in diesem Zusammenhang vorgesehene Funktion nicht erreichen (durch Kopieren des Wertes intern innerhalb des Behälters). Dies führt oft zur Verwendung von shared_ptr, wo das gemeinsame Eigentum nicht wirklich die beabsichtigte Bedeutung ist. In diesen Fällen schlage ich (wo möglich) vor, die Boost-Pointer-Container-Klassen (ptr_vector, und so weiter) zu verwenden, die die (häufig gewünschte) Semantik eines Containers mit übertragbaren, aber einzigen (nicht geteilten) Eigentumsrechten bereitstellen.

Sie sollten immer über den Besitz Ihrer Objekte nachdenken: In den meisten Fällen hat jedes Objekt bei einem sauberen Systemdesign einen offensichtlichen Eigentümer, und die Eigentümerschaft muss nicht geteilt werden. Dies hat den Vorteil, dass es einfach ist, genau zu sehen, wo und wann Objekte freigegeben werden, und kein Overhead für die Referenzzählung erforderlich ist.

[bearbeitet die neue unique_ptr beachten]

+1

+1 für die Erwähnung, dass shared_ptr oft überbenutzt wird! – mmmmmmmm

+0

Wie auch immer, es gibt noch einige saubere Szenarien, in denen shared_ptr nützlich ist. Ich habe ein Threading-Framework, wo die Thread-Informationen in einem shared_ptr gespeichert werden, eine Kopie wird dem Thread-Objekt selbst gegeben und freigegeben, wenn die Threads enden, wird eine andere Kopie dem Aufrufer gegeben. Dies ist die sauberste Methode, um die Bereinigung nach dem Ende eines Threads zu gewährleisten, ermöglicht es einem Aufrufer jedoch, den aktuellen Status des Threads sicher zu verfolgen. – mmmmmmmm

+0

Möglicherweise "in den meisten Fällen, mit einem sauberen Systemdesign" war zu stark. Wahre gemeinsame Eigentumsverhältnisse sind nicht so selten (wenn auch viel seltener als Einzeleigentum). Danke, dass Sie ein gutes Beispiel geben. –

2

Sie sollten wahrscheinlich shared_ptr<> verwenden. Es ist schwierig, genauer zu sein, ohne zu wissen, was genau Sie tun möchten. Am besten lesen Sie documentation und sehen Sie, ob es tut, was Sie brauchen.

Der Leistungsunterschied ist höchstwahrscheinlich vernachlässigbar. Nur im Extremfall kann es zu einem spürbaren Einschlag kommen, etwa beim Kopieren dieser Zeiger viele Millionen Mal pro Sekunde.

+0

Der Leistungsunterschied ist NICHT vernachlässigbar. Da der Overhead von shared_ptr nicht nur das Inkrementieren und Dekrementieren des Referenzzählers ist. Es gibt auch ein zweites neues/Löschen pro Objekt für die Wartungsinformationen! Und da Heap langsam ist, kann dies in manchen Situationen schlecht sein. Außerdem kann shared_ptr zu Speicherlecks führen, wenn Sie Zirkelverweise haben (die mit weak_ptr gelöst werden können; aber Sie müssen viel mehr denken!). – mmmmmmmm

+0

@rstevens: Sie können 'make_shared()' verwenden, das nur eine Zuweisung durchführt. Wie auch immer, typischerweise werden Leistungsengpässe nicht in den Zeigern verwendet, und ich vermute, dass die Bedenken der OP eine vorzeitige Optimierung sind. Außerdem müssen Sie über Speicherlecks nachdenken, egal welche Art von Smart Pointer oder nicht-Smart Pointer Sie verwenden. Wenn überhaupt, erleichtert 'shared_ptr' /' weak_ptr' die Handhabung. – sth

1

Ich bevorzuge shared_ptr, auto_ptr kann eine Menge Ärger verursachen und seine Verwendung ist nicht zu intuitiv. Wenn Sie erwarten, dass dieses Objekt in einen STL-Container eingefügt wird, möchten Sie sicher shared_ptr verwenden.

Über die Leistung haben Sie eine Kosten, aber das ist minimal und Sie können es die meiste Zeit ignorieren.

+1

Leistungskosten können ziemlich hoch sein! Stellen Sie sicher, dass Sie nach der Verwendung von SmartPtrs ein Profil erstellen, um zu sehen, ob die Auswirkung akzeptabel ist. – RedX

1

Hängt davon ab.
Gemeinsame Zeiger haben eine bessere Verwendung als auto_ptr, die die ungewöhnliche Eigenschaft besitzen, den Besitz von Zuweisungen zu ändern.
Auch auto_ptr kann nicht in Containern verwendet werden.
Sie können auto_ptr auch nicht als Rückgabewerte verwenden, wenn Sie die Eigentumsrechte nicht übertragen möchten.
Gemeinsame Zeiger haben alle Vorteile von Smartpointern, haben die entsprechenden Operatoren überladen, um sich wie ein Zeiger zu verhalten, und können in Containern verwendet werden. Damit sind sie nicht billig zu verwenden.
Sie müssen Ihre Bedürfnisse analysieren, um zu entscheiden, ob Sie tatsächlich etwas gewinnen die shared_pointer Umsetzung Gemeinkosten

+0

Falsch: auto_ptr kann in Containern verwendet werden ... wegen seiner rohen Eigenschaft ... (Die Verwendung in Containern ist der Grund für diese Eigenschaften !!!) – mmmmmmmm

+0

@rstevens: Ich habe keine Ahnung, was dein Kommentar bedeutet.auto_ptr' erfüllt nicht eine der grundlegendsten Anforderungen für Elemente in Standardcontainern. Nach einer Kopie oder Zuweisung einer 'auto_ptr'-Quelle und -Senke sind diese nicht gleichwertig.' auto_ptr' sollte NICHT in Standardcontainern verwendet werden. – Cratylus

+0

@ user384706: auto_ptr ist so gebaut, dass es in Standardcontainern wie std :: vector und std :: list verwendbar ist. Es kann Probleme in anderen Containern verursachen, aber da std :: auto_ptr und std :: - Container zusammen entwickelt werden, funktionieren sie garantiert zusammen. – mmmmmmmm

0

Nur shared_ptr. Mit auto_ptr können Sie NUR EINE Referenz auf Ihr Objekt haben. Auch auto_ptr ist nicht langsamer, es muss schneller als shared_ptr arbeiten.

Um solche Fragen nicht zu stellen, müssen Sie wissen, wie diese intelligenten Zeiger funktionieren.

auto_ptr nur Zeiger auf Ihr Objekt speichern und es in seinem Destruktor zerstören.

Das Problem von auto_ptr ist, dass wenn Sie versuchen, es zu kopieren, es stoppt, um auf Ihr Objekt zu zeigen.

Zum Beispiel

auto_ptr a_ptr (new someclass);

auto_ptr another_ptr = aptr; // danach zeigt ein anderes_ptr auf deine Klasse, aber a_ptr zeigt nicht mehr darauf!

Deshalb empfehle ich Sie nicht, auto_ptr zu verwenden.

Geteilter Zeiger, der zählt, wie viel intelligente Zeiger auf Ihr Objekt zeigen und Ihr Objekt zerstören, wenn es keine Zeiger mehr darauf gibt. Deshalb können Sie mehr als einen Zeiger auf Ihr Objekt haben.

Aber Shared Pointer ist auch nicht perfekt.Und wenn du in deinem Programm einen zyklischen Graph hast (wenn die Klassen A und B und A ein Element shared_ptr haben, das auf B zeigt und B die Mitgliedsobjekte shared_ptr auf A zeigen), dann werden A und B niemals gelöscht und du wirst habe Speicher lecken.

Um korrekten Code mit shared_ptr zu schreiben, müssen Sie vorsichtig sein und auch weak_ptr verwenden. Weitere Informationen finden Sie hier http://www.boost.org/doc/libs/1_45_0/libs/smart_ptr/smart_ptr.htm