2014-11-06 5 views
6

Ich habe Objektstruktur, die von shared_ptr s gemacht wird, plus weak_ptr s, um Zirkularität zu vermeiden. Raw Pointer sind ein No-Go als boost::serialization muss freigegebene und schwache Zeiger beim Deserialisieren via Objekt-Tracking als Serialisierungszeit wiederherstellen. Objektlebensdauermuster sind komplex (Partikelsimulation), aber vollständig vorhersagbar. Immer wenn ich weak_ptr::lock() benutze, bin ich sicher, dass der Zeiger immer noch gültig ist. Normalerweise verwende ich lock().get(), da ich das Objekt nur für eine sehr kurze Zeit brauche.Portable Hack zum Leak rohe Zeiger von weak_ptr

Jetzt hat lock().get() Auswirkungen auf die Leistung, da es die gemeinsame Zählung erhöht (in lock()), und dann dekrementiert es kurz danach (die temporäre shared_ptr ist zerstört).

Diese boost.devel post von 2002 sagt, dass, während weak_ptr entwickelt wurde, die Funktionalität der Rohzeiger direkt betrachtet wurde der Zugriff (zu unsafe_get oder leak genannt werden), aber nie hat es auf die tatsächliche Umsetzung. Seine Abwesenheit zwingt Programmierer, unter gegebenen Bedingungen eine suboptimale Schnittstelle zu verwenden.

Nun ist die Frage, wie die unsafe_get/leak, in anderen Worten zu emulieren, erhalten die Rohzeiger von weak_ptr, ungültig auf Gefahr des Programmierers, nur zu lesen (nicht zu schreiben) Daten. Ich kann mir vorstellen, dass einige Tricks wie das Finden des Offsets des rohen Zeigers innerhalb von shared_ptr oder dergleichen den Job erledigen würden.

Ich benutze boost::shared_ptr, aber die Lösung könnte auch für C++ 11 std::shared_ptr arbeiten.

+2

Gute Frage, aber es klingt ehrlich wie rohe Zeiger wäre hier der bessere Deal. Verwalten Sie die Objekte separat (z. B. alle Ihre Partikel in einem Container zusammenfassen) und weiche Zeiger auf diese weiter. –

+0

Ich denke, selbst wenn Sie nur das Objekt für eine kurze Zeit verwenden, sollten Sie das 'shared_ptr' halten, während Sie es verwenden:' auto s = w.lock(); if (s) s-> doSomething(); 'Ich denke mit' lock(). get() 'ist eine schlechte Übung und nicht schneller. Es ist möglich, dass genau die Aktion der Verwendung des Zeigers tatsächlich das letzte 'shared_ptr' zum Sterben auslösen könnte. –

+1

Wenn Sie wissen, dass die Schwachstellen auf Objekte ohne ".lock()" zeigen, verwenden Sie kein 'weak_ptr'. Haben Sie nebenbei bemerkt, dass dies ein Leistungsengpass ist? – Yakk

Antwort

3

Ich schlage vor, Sie halten einfach einen weak_ptr und einen rohen Zeiger und verwenden den rohen Zeiger direkt als eine Optimierung, wenn Sie wissen, dass es sicher ist, dies zu tun. Sie könnten den weak_ptr und den zugehörigen rohen Zeiger in einer Klasse mit einem unsafe_get einpacken, wenn Sie möchten.

+1

Eine wichtige Anmerkung ist, dass es absolut gültig ist, rohe Zeiger und Referenzen sogar seit C++ 11 zu speichern, zu verwenden und weiterzugeben, solange diese Zeiger so verstanden werden, dass sie die Lebensdauer des Objekts nicht "besitzen" oder verwalten - die Regel für Sicherheit ist, dass Sie wissen müssen, dass einige "Besitzer" (wie ein 'shared_ptr' zum selben Objekt) sie überleben. Natürlich besitzt ein 'weak_ptr' nicht das Objekt, auf das es verweist, daher gibt es dort mögliche Probleme, wenn Sie nicht sicher sein können, wie lange dieses Objekt existiert - ist es möglich, dass ein anderer Code das letzte' shared_ptr' zerstören könnte? 'weak_ptr'-referenziertes Objekt? – Steve314

+1

Kein Zweifel, deshalb gibt es im Standard keinen 'unsafe_lock'. Die Verwendung von 'lock(). Get()' (dh das 'shared_ptr' wird nicht beibehalten, solange Sie den rohen Zeiger verwenden) ist ebenfalls ziemlich zerbrechlich. – Steve314

+0

@ Steve314: OT: Ich denke nicht, dass es das Geschäft von C++ ist, wegen möglicher Gefahren einzuschränken. Ich stimme zu, dass es nicht gut ist, gefährliche Praktiken zu fördern, aber etwas nicht einzubeziehen, weil es missbraucht werden könnte, ist ein bisschen Erziehung. – eudoxos

5

Seit Sie nach einem tragbaren Hack gefragt.

Ein lustiger Teil des Codes in boost's weak_ptr.hpp gefunden ist:

template<class T> class weak_ptr 
{ 
    ... 

public: 

    ... 

// Tasteless as this may seem, making all members public allows member templates 
// to work in the absence of member template friends. (Matthew Langston) 

#ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS 

private: 

    template<class Y> friend class weak_ptr; 
    template<class Y> friend class shared_ptr; 

#endif 

    element_type * px;   // contained pointer 
    boost::detail::weak_count pn; // reference counter 

}; // weak_ptr 

Was bedeutet, wenn Sie Auftrieb mit der Option BOOST_NO_MEMBER_TEMPLATE_FRIENDS kompilieren, werden Sie öffentlich Zugang zum Mitglied px von weak_ptr haben, die ein Rohzeiger zu sein scheint zum Elementtyp.

+1

Ich bin mir nicht sicher, wie zukunftssicher das ist ... Was ist Boosts Strategie, die Binärkompatibilität in zukünftigen Versionen zu brechen? Denn wenn sie es erlauben (sehr gültig), dann ist dieser Hack leider nicht tragbar. Und es wird auch nicht mit 'std :: weak_ptr' funktionieren. –

+1

@KonradRudolph Nun, wenn es zukunftssicher wäre, wäre es kein Hack. Aber zu einem bestimmten Zeitpunkt ist dieser Hack so portabel wie die Boost-Bibliotheken, er kann nur brechen, wenn du deine Boost-Version aktualisierst, aber genauso wie jede andere normale Funktion von Boost. – Drax

+0

Eine andere Möglichkeit könnte sein, die Freundschaft zu nutzen: spezialisieren Sie einen weak_ptr mit einem speziellen Typ Y, und greifen Sie dann auf px: 'template <> weak_ptr {/ * friend of weak_ptr * /};'. Der Vorlagenfreund ist eine generische Zugriffshintertür. – NicholasM