Frage

Ich habe eine Bibliothek geschrieben, die Verweise auf mehrere verwandten Objekttypen verfügbar macht. Alle diese Objekte haben ihre Lebensdauer durch die Bibliothek intern über boost::shared_ptr verwaltet

Ein Benutzer der Bibliothek der Lage sei, auch zu wissen, von Natur aus der Bibliothek, das Lebensdauern von einem der exponierten Objekte. So konnten sie Zeiger speichern oder Verweise auf diese Objekte halten. Es wäre sinnvoll für sie, dies zu tun und wissen, wann diese Objekte nicht mehr gültig sind.

Aber ich fühle mich schuldig, meine Benutzer zu zwingen, vernünftig zu sein.

Ist es akzeptabel, eine Bibliothek haben weak_ptr der seine Objekte aussetzen? Haben andere Bibliotheken das getan?

Ich habe diese Bibliothek Verwendung in Anwendungen profiliert und haben festgestellt, es zu unternehmenskritischen sein weak_ptr aussetzen ausschließlich.

Wäre es klüger sein, API Anpassung haben Funktionen ausgesetzt, die entweder eine Referenz oder ein weak_ptr oder auf ein beliebiges Objekt der Belichtung eines weak_ptr sich fähig zu machen?

War es hilfreich?

Lösung

Wenn die smart_ptrs sind bereits direkt zugänglich für die Benutzer der Bibliothek, dann haben sie haben bereits Zugang zu den weak_ptrs, einfach über den Konstruktor der entsprechenden weak_ptr. Aber wenn die smart_ptrs alle intern in der Bibliothek sind, das ist eine andere Geschichte.

In diesem Fall würde ich empfehlen, jedes Objekt zu lassen umkippen weak_ptrs sich, zusätzlich zu jedem anderen Zugriff auf Ihre Bibliothek bietet. Das gibt dem Benutzer die größtmögliche Flexibilität: wenn sie einen weak_ptr benötigen, sie sofortigen Zugriff auf ihn haben; wenn sie einen shared_ptr benötigen, können sie es leicht zu bekommen; und wenn sie nur Zugriff auf das Objekt müssen selbst, können sie die intelligenten Zeiger vollständig ignorieren.

Natürlich weiß ich nicht, was Ihre Bibliothek funktioniert oder wie es verwendet oder entwickelt. Das könnte meine Empfehlung ändern.

Andere Tipps

Coming up mit gewundenen Mechanismen bei den Objekten Ihrer Bibliothek zu bekommen führt nur in Menschen nicht Ihre Bibliothek. Wenn die Semantik der Bibliothek diktieren müssen Sie Menschen mit weak_ptrs haben, gibt es keinen Weg, um den Benutzer zu wissen, dass die Gegenstände irgendwann weggehen kann. Machen Sie die Schnittstelle so viele Informationen über die Nutzung der Bibliothek wie möglich auszudrücken, hält Dokumentation und macht es unendlich viel leichter zu verwenden.

Sie können nicht Design um schlecht / unerfahrenen Anwender.

Wenn Sie geben Ihren Kunden weak_ptrs zugreifen können sie sperren sie nur shared_ptrs zu schaffen und die Zerstörung von Objekten zu verzögern enden. Das könnte zu Problemen mit Ihrer Bibliothek.

Ich schlage vor, eine weak_ptr in einer anderen Klasse Verpackung und dem Anrufer eine shared_ptr zu, dass zu geben. Auf diese Weise können sie einfach nicht weak_ptr<T>::lock() nennen. Sie scheinen zu Leistungseinschränkungen, die beeinflussen können, wie Sie es umsetzen, aber ein shared_ptr<InterfaceClass> könnte ein guter Weg zu gehen, und hält die Klasse mit den weak_ptr internen Ihrer Bibliothek.

Auf diese Weise können auch diese Implementierungsdetails aus Ihrer Bibliothek Schnittstelle halten und Sie können, wie Sie es ohne Änderung Ihrer Schnittstelle implementieren ändern.

Ich sehe kein Problem mit Belichtungs weak_ptrs, zumal TR1 hat ähnliche intelligente Zeiger (PDF).

TR1 wird weitgehend von Visual Studio und GCC implementiert, aber da draußen einige der anderen Compiler nicht. Aber wenn es in allen Compilern implementiert ist Ihnen wichtig sind, sollten Sie das API zu überarbeiten, anstatt diese intelligente Zeiger zu belichten.

Wenn Sie sowohl Trap ungültige Verwendung der Bibliothek wollen (versuchen, die Objekte zuzugreifen, wenn sie gelöscht wurden) sowie eine High-Performance-API (kein weak_ptr der und shared_ptr der in der API), dann könnte man erwägen haben eine andere API für Debug- und nondebug baut.

Lassen Sie uns der Einfachheit halber an, dass Sie nur eine Klasse von Objekten haben Sie belichten; nennen diese Klasse Object. Der Zeigertyp, die Sie von der API geben die internen Objekte für den Zugriff wird dann wie folgt definiert:

#ifdef DEBUG
typedef ObjectPtrFacade ObjectPtr 
#else
typedef Object * ObjectPtr;
#endif

Hier ist die Fassade ist die Klasse, die Sie schreiben. Es funktioniert in etwa wie folgt aus:

class ObjectPtrFacade {
public:
    ObjectPtrFacade(Object *o) : wptr(o) { }
    // copy constructor and assignment here etc. (not written)
    Object * operator -> () const { return access(); }
    Object & operator * () const { return *access(); }
private:
    Object * access() { 
      assert(wptr.use_count() > 0);
      return (Object *)(wptr.lock());
    }
    weak_ptr<Object> wptr; 
}

Auf diese Weise, wenn Sie ein Debug-Build bauen, haben Sie eine besondere Art von Smart-Pointer im Einsatz, das behauptet, bevor das Objekt zugreifen, dass sein use_count () höher als Null ist, das heißt, dass das Objekt noch vorhanden ist. Wenn das Objekt freigegeben wurde, können Sie eine versagende assert bekommen, was besser ist als eine Null-Zeiger-Referenz.

Im Allgemeinen ist es natürlich so, dass weak_ptr der Verwendung von nicht hilft, wenn Sie „dumm“ Nutzer der API haben, weil sie Sperre nennen könnte () und dann noch eine Null-Pointer-Referenz nach dem weak_ptr machen gibt eine shared_ptr des leer ist ...

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top