2009-02-26 5 views
2

Ich habe ein paar Fragen (here und here) über Speicherverwaltung, und immer jemand schlägt vor, dass ich boost :: shared_ptrs verwenden.Gibt es Gründe, Boost :: shared_ptrs nicht zu verwenden?

Angesichts der Tatsache, wie nützlich sie zu sein scheinen, überlege ich ernsthaft, meine gesamte Anwendung auf boost :: shared_ptrs umzustellen.

Bevor ich jedoch mit beiden Füßen einspringe und das mache, wollte ich fragen - Hat jemand schlechte Erfahrungen mit boost :: shared_ptrs gemacht? Gibt es eine Falle, um sie zu benutzen, auf die ich achten muss?

Gerade jetzt, scheinen sie fast zu gut, um wahr zu sein - kümmert sich um die meisten meiner Müllsorgen Bedenken automatisch. Was ist der Nachteil?

Antwort

4

Der Nachteil ist, dass sie nicht frei sind. Sie sollten insbesondere shared_ptr/ nicht verwenden, wenn scoped_ptr/scoped_array (oder einfache alte Stapelzuweisung) tun. Sie müssen Zyklen manuell mit weak_ptr brechen, wenn Sie welche haben. Die Vektorfrage, zu der Sie verlinken, ist ein Fall, in dem ich nach einer shared_ptr, die zweite Frage, die ich nicht erreichen würde. Nicht kopieren ist eine vorzeitige Optimierung, besonders wenn die String-Klasse es bereits für Sie tut. Wenn die String-Klasse als Referenz gezählt wird, ist sie auch in der Lage, COW korrekt zu implementieren, was mit dem shared_ptr<string>-Ansatz nicht wirklich möglich ist. Mit Willy-Nilly wird auch "Interface Friktion" mit externen Bibliotheken/Apis einführen.

+0

Zeichenfolgen verwenden normalerweise nicht COW. Es funktioniert nicht gut mit Multithread-Anwendungen, daher haben die meisten Implementierungen es wieder fallengelassen. Was bedeutet, dass Zeichenkettenkopien etwas teuer sind. – jalf

+0

Die String-Implementierung von GCC verwendet immer noch COW IIRC. Aber mit C++ 0x werden sie * wahrscheinlich * nicht erlaubt sein (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2668.htm) - und gute Riddance. –

0

Dynamischer Arbeitsspeicher-Overhead (d. H. Zusätzliche Zuweisungen) plus der gesamte mit Verweiszählern verknüpfte Aufwand.

2

Boost gemeinsame Zeiger oder eine andere Technik der Speicherverwaltung in C++ ist kein Allheilmittel. Es gibt keinen Ersatz für sorgfältige Codierung. Wenn Sie boost :: shared_ptr verwenden, achten Sie auf den Objektbesitz und vermeiden Sie zirkuläre Referenzen. Sie müssen Zyklen explizit unterbrechen oder boost :: weak_ptr verwenden, falls erforderlich.

Achten Sie auch darauf, boost :: shared_ptr immer für eine Instanz zu verwenden, sobald sie zugewiesen ist. Auf diese Weise sind Sie sicher, dass Sie keine Referenzen haben werden. Sie können beispielsweise sicherstellen, dass Factory-Methoden verwendet werden, die das neu erstellte Objekt in einem shared_ptr zurückgeben.

typedef boost::shared_ptr<Widget> WidgetPtr; 
WidgetPtr myWidget = Widget::Create(); 
1

Ich benutze shared_ptr oft.

Da Shared_ptr by-value kopiert werden, können Sie die Kosten für das Kopieren des Pointer-Werts und eines Referenzzählers übernehmen, aber wenn boost :: intrusive_ptr verwendet wird, muss die Referenzanzahl zu Ihrer Klasse hinzugefügt werden kein zusätzlicher Overhead über dem eines rohen Pointers.

Nach meiner Erfahrung, mehr als 99% der Zeit, ist der Overhead des Kopierens boost :: shared_ptr Instanzen in Ihrem Code unbedeutend. Gewöhnlich, wie C. A. R. Hoare bemerkte, ist eine vorzeitige Optimierung sinnlos - die meiste Zeit wird anderer Code wesentlich mehr Zeit benötigen als die Zeit, um kleine Objekte zu kopieren. Ihre Laufleistung kann variieren. Wenn beim Profiling angezeigt wird, dass das Kopieren ein Problem darstellt, können Sie zu störenden Zeigern wechseln.

Wie bereits oben erwähnt, müssen Zyklen durch Verwendung eines weak_ptr unterbrochen werden, oder es tritt ein Speicherleck auf. Dies wird bei Datenstrukturen wie z. B. einigen Graphen passieren. Wenn Sie jedoch beispielsweise eine Baumstruktur erstellen, bei der die Blätter niemals nach hinten zeigen, können Sie einfach shared_pointers für Knoten des Baums ohne Probleme verwenden.

Die Verwendung von shared_ptr vereinfacht den Code erheblich, erleichtert das Lesen und vereinfacht die Pflege. In vielen Fällen ist die richtige Wahl die richtige Wahl.

Wie bereits erwähnt, ist die Verwendung von scoped_ptr (oder scoped_array) in einigen Fällen die richtige Wahl. Wenn der Pointe nicht freigegeben wird, verwenden Sie keine geteilten Pointer!

Schließlich bietet der neueste C++ - Standard die std :: tr1 :: shared_ptr Vorlage, die jetzt auf den meisten Plattformen ist, obwohl ich glaube nicht, dass es einen intrusiven Zeigertyp für tr1 gibt (oder besser, es könnte sein , aber ich habe selbst nichts davon gehört).

Verwandte Themen