2009-03-10 8 views
4

Ich habe eine Bibliothek geschrieben, die Verweise auf mehrere verwandte Objekttypen verfügbar macht. Alle diese Objekte haben ihre Lebensdauern intern von der Bibliothek verwaltet. Ein Benutzer der Bibliothek könnte aufgrund der Art der Bibliothek auch die Lebensdauern eines der belichteten Objekte kennen. So könnten sie Zeiger speichern oder Verweise auf diese Objekte behalten. Es wäre vernünftig für sie, dies zu tun und zu wissen, wann diese Objekte nicht mehr gültig sind.Ist es ratsam, den Zugriff auf weak_ptr in einer Bibliotheksschnittstelle zu ermöglichen?

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

Ist es akzeptabel, dass eine Bibliothek weak_ptr 's zu ihren Objekten aussetzt? Haben andere Bibliotheken dies getan?

Ich habe die Verwendung dieser Bibliothek in Apps profiliert und festgestellt, dass sie zu missionskritisch ist, um ausschließlich weak_ptr offenzulegen.

wäre es klüger, passend zu haben API-Funktionen belichten entweder eine Referenz oder ein weak_ptr oder jedes Objekt fähig zu machen, einen weak_ptr sich auszusetzen?

+0

Sie fragen uns, ob Sie weak_ptrs aufdecken sollten, aber dann sagen Sie, dass Profiling zeigt, dass Sie weapon_ptrs nicht überall verwenden können - richtig? Was würden Sie stattdessen für diese leistungskritischen Fälle bereitstellen? Eine rohe Referenz? Oder ein shared_ptr? –

+0

@j_random_hacker: Die Bibliothek enthält bereits Referenzen. Ich überlege, passende API-Funktionen zu finden, die entweder eine Referenz oder ein weak_ptr verfügbar machen. –

+0

Hmm. Ich schlage vor, dass Sie sweat_ptrs anstelle von shared_ptrs vorschlagen, weil Sie versuchen, den aufrufenden Code zu bekommen, um Fehler zu erkennen, richtig? Aber ich denke, dass der aufrufende Code das schwache_ptr sowieso in ein shared_ptr umwandeln muss, damit man nicht viel Schutz bei ihnen kauft - ganz womöglich wird der ... –

Antwort

6

Wenn die smart_ptr s den Benutzern der Bibliothek bereits direkt zugänglich sind, haben sie bereits Zugriff auf die weak_ptr s, einfach über den entsprechenden Konstruktor weak_ptr. Aber wenn die smart_ptr s alle intern in der Bibliothek sind, ist das eine andere Geschichte.

In diesem Fall würde ich empfehlen, jedes Objekt weak_ptr s sich selbst übergeben zu lassen, zusätzlich zu jedem anderen Zugriff, den Ihre Bibliothek bietet. Das gibt den Benutzern die größte Flexibilität: Wenn sie eine weak_ptr benötigen, haben sie sofortigen Zugriff darauf; wenn sie eine shared_ptr brauchen, können sie es leicht bekommen; und wenn sie nur Zugriff auf das Objekt selbst benötigen, können sie die Smartpointer vollständig ignorieren.

Natürlich weiß ich nicht, was Ihre Bibliothek tut oder wie sie verwendet oder entworfen wird. Das könnte meine Empfehlung ändern.

+0

Die Bibliothek verwendet zur Zeit intern nur shared_ptr. –

1

Ich sehe kein Problem mit dem Aussetzen von weak_ptrs, vor allem angesichts der TR1 has similar smart pointers (PDF).

TR1 wird größtenteils von Visual Studio und GCC implementiert, aber nicht von anderen Compilern. Aber wenn es in allen Compilern, die Ihnen wichtig sind, implementiert ist, möchten Sie vielleicht die API überarbeiten, um stattdessen diese Smart Pointer verfügbar zu machen.

2

Wenn Sie Ihren Kunden Zugriff auf weak_ptr s geben, können sie diese einfach sperren, um shared_ptr s zu erstellen und die Zerstörung von Objekten zu verzögern. Das könnte Probleme mit Ihrer Bibliothek verursachen.

Ich schlage vor, eine weak_ptr in eine andere Klasse zu legen und dem Anrufer eine shared_ptr zu geben. Auf diese Weise können sie nicht einfach weak_ptr<T>::lock() anrufen. Sie scheinen Leistungseinschränkungen zu haben, die Ihre Implementierung beeinflussen könnten, aber shared_ptr<InterfaceClass> könnte ein guter Weg sein, und behalten Sie die Klasse mit weak_ptr intern in Ihrer Bibliothek.

Auf diese Weise behalten Sie diese Implementierungsdetails auch aus Ihrer Bibliotheksschnittstelle heraus, und Sie können die Art der Implementierung ändern, ohne die Benutzeroberfläche zu ändern.

4

Die Verwendung von verschachtelten Mechanismen, um auf die Objekte Ihrer Bibliothek zuzugreifen, führt nur dazu, dass Benutzer Ihre Bibliothek nicht verwenden. Wenn die Semantik der Bibliothek vorschreibt, dass Sie Leute haben müssen, die weak_ptrs verwenden, gibt es keine Möglichkeit, dass der Benutzer weiß, dass die Objekte irgendwann weggehen können. Machen Sie der Benutzeroberfläche möglichst viele Informationen über die Verwendung der Bibliothek, halten Sie die Dokumentation fest und erleichtern Sie die Verwendung.

Sie können nicht um schlechte/unerfahrene Benutzer entwerfen.

0

Wenn Sie sowohl die ungültige Verwendung der Bibliothek (versuchen, auf die gelöschten Objekte zuzugreifen) als auch eine Hochleistungs-API (keine Schwachstellen und Shared_Ptrs in der API) abfangen wollen, dann könnten Sie darüber nachdenken habe eine andere API für Debug- und Nichtdebug-Builds.

Nehmen wir zur Vereinfachung an, dass Sie nur eine Klasse von Objekten haben, die Sie aussetzen; rufe dieses Objekt der Klasse auf. 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 einen Debug-Build bauen, haben Sie eine besondere Art von Smart-Pointer im Einsatz, die vor dem Zugriff auf das Objekt behauptet, dass seine use_count() höher als Null ist, dh dass das Objekt noch existiert. Wenn das Objekt freigegeben wurde, erhalten Sie eine fehlgeschlagene Bestätigung, die besser als eine Nullzeigerreferenz ist.

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