2015-01-02 14 views
19

Ich dachte, es ist sehr neugierig, wenn ich entdeckte, dass der Standard definiert std::unique_ptr und std::shared_ptr auf zwei völlig verschiedene Arten in Bezug auf eine Deleter, die der Zeiger besitzen kann. Hier ist die Erklärung von cppreference::unique_ptr und cppreference::shared_ptr:Deleter-Typ in unique_ptr vs shared_ptr

template< 
    class T, 
    class Deleter = std::default_delete<T> 
> class unique_ptr; 

template< class T > class shared_ptr; 

Wie Sie die unique_ptr sehen „rettet“ die Art des dem Deleter-Objekt als Vorlage Argument. Dies kann auch in der Art, wie der Deleter aus dem Zeiger auf später abgerufen wird:

// unique_ptr has a member function to retrieve the Deleter 
template< 
    class T, 
    class Deleter = std::default_delete<T> 
> 
Deleter& unique_ptr<T, Deleter>::get_deleter(); 

// For shared_ptr this is not a member function 
template<class Deleter, class T> 
Deleter* get_deleter(const std::shared_ptr<T>& p); 

Kann jemand die rationale hinter diesem Unterschied erklären? Ich favorisiere eindeutig das Konzept für unique_ptr Warum wird dies nicht auf shared_ptr aswell angewendet? Warum sollte get_deleter im zweiten Fall eine Nichtmitgliedsfunktion sein?

+2

Jemand muss den ursprünglichen Vorschlag ausgraben, aber meine Vermutungen: Nicht die Deleter als Vorlage Argument macht 'shared_ptr' einfacher zu bedienen, aber Sie müssen die Art löschen Kosten bezahlen. Wenn man "get_deleter" zu einem Mitglied macht, wird das Schreiben von generischem Code mit 'shared_ptr ' mühsamer - man müsste 'sp.template get_deleter ()' anstelle von 'get_deleter (sp)' schreiben. Deshalb ist 'std :: get' ein Nichtmitglied. –

+3

Expandiert etwas auf was @ T.C. sagte, eines der Entwurfsziele für 'unique_ptr' ist, dass es (fast) Null Overhead haben sollte. Das Löschen des Löschertyps ist praktisch, führt jedoch zu Laufzeit-Overhead aus dem Löschvorgang, daher ist es für 'unique_ptr' weniger geeignet als für' shared_ptr'. – wakjah

+0

Sie sollten außerdem beachten, dass 'shared_ptr p = make_shared ()' ist macht das Richtige, auch wenn 'Base' keinen virtuellen Destruktor hat. [Beweis] (http://coliru.stacked-crooked.com/a/f3a50f90e00d4e58). –

Antwort

18

Hier können Sie den ursprünglichen Vorschlag für intelligente Zeiger finden: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html

Es beantwortet Ihre Frage ganz genau:

Da der deleter nicht Teil der Typ ist, wird die Allokationsstrategie ändert sich nicht brechen Quell- oder Binärkompatibilität und erfordert keine Neukompilierung des Clients.

Dies ist auch nützlich, da die Kunden von std::shared_ptr einige mehr Flexibilität gibt, zum Beispiel shared_ptr Instanzen mit unterschiedlichen Löscher kann im gleichen Behälter aufbewahrt werden.

Da die shared_ptr Implementierungen sowieso einen gemeinsamen Speicherblock benötigen (zum Speichern der Referenzzählung) und weil es im Vergleich zu unformatierten Zeigern bereits einen Overhead geben muss, ist das Hinzufügen eines gelöschten Deletters keine große Sache Hier.

unique_ptr auf der anderen Seite sind keine Overhead zu haben und jede Instanz muss seine Deleter einbetten, so dass es ein Teil des Typs ist, ist die natürliche Sache zu tun.

+0

Wie wird der gelöschte Delete-Typ btw genannt? – WorldSEnder

+0

@WorldSEnder: Dies liegt an der Implementierung, aber der übliche Weg besteht darin, den konkreten Deleter in eine Template-Klasse zu kapseln, die eine Schnittstelle zum Löschen eines T * implementiert (erbt). Wenn die Referenzzählung null erreicht, ruft die Implementierung die virtuelle Methode auf, und dieser Aufruf wird an die Einbettungsklasse gesendet, die wiederum den konkreten Deleter aufruft. Es ist der gleiche Mechanismus wie für std :: function. – Horstling

+1

Beachten Sie, dass 'rohe' Implementierung von 'std :: function' und wahrscheinlich' shared_ptr' in der Praxis schneller ist als eine vtable-basierte, aber nur wenige Std-Bibliotheken verwenden sie (siehe 'schnellstmögliche Delegaten' über Google). Die vtable-Implementierung ist nur am einfachsten zu verstehen, da sie wie normales C++ aussieht. – Yakk

Verwandte Themen