2015-01-02 15 views
19

Standardın std::unique_ptr ve std::shared_ptr tanımlayıcısının işaretçinin sahip olabileceği bir Deleter ile ilgili iki farklı şekilde tanımladığını keşfettiğimde çok meraklı olduğunu düşündüm. İşte cppreference::unique_ptr ve cppreference::shared_ptr gelen beyanıdır:unique_ptr vs shared_ptr'de deleter tipi

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

template< class T > class shared_ptr; 

Eğer unique_ptr "kaydeder" Bir şablon argüman olarak Deleter-nesne tipi görebileceğiniz gibi.

// 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); 

birisi bu farkın arkasında rasyonel açıklayabilir: Bu aynı zamanda Deleter sonradan pointer alınır şekilde görülebilir? unique_ptr konseptini açıkça destekledim, bu neden shared_ptr için geçerli değil? Ayrıca, neden bu durumda get_deleter üye olmayan bir işlev olur? İşte

+2

Birisi orijinal önerisini kazıp zorunda, ama olacak benim eğitimli tahminler: şablon argümanı kullanmak daha kolay shared_ptr' 'yapar, ama sen tür silme masraflarını ödemeniz gerekiyor olarak deleter olmaması. Yapımı 'üyesi alarak jenerik kod yazarken yapacak get_deleter' bir' Shared_ptr 'daha sıkıcı - Eğer ()' yerine 'get_deleter (sp)' arasında 'sp.template get_deleter iletişim kurmanız gerekir. Bu yüzden std :: get' bir üye değildir. –

+3

@ T.C'de hafifçe genişliyor. 'unique_ptr' için tasarım hedeflerinden biri de, (çok fazla) sıfır yüke sahip olması gerektiğidir. Silme Deleter tip ') (uygundur ama silinmekten zaman yükü çalıştırmak tanıtmaktadır, bu nedenle' – wakjah

+0

Ayrıca çünkü farkı, 'Shared_ptr p = make_shared dikkat etmelidir shared_ptr' için daha unique_ptr'' az uygundur 'Base' sanal yok edici olmasa bile doğru olanı yapar. [Geçirmez] (http://coliru.stacked-crooked.com/a/f3a50f90e00d4e58). –

cevap

18

akıllı işaretçiler için orijinal öneri bulabilirsiniz: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1450.html

Oldukça hassas bir şekilde soruya cevap verir:

deleter kesilmez tahsisi strateji değiştirerek, tip bir parçası olmadığından Kaynak veya ikili uyumluluk ve istemci yeniden derleme gerektirmez. Farklı silicilere ile shared_ptr örnekleri aynı kap içinde muhafaza edilebilir, örneğin, biraz daha fazla esneklik std::shared_ptr istemcileri verir, çünkü

bu da yararlıdır.

Ayrıca, shared_ptr uygulamalarının bir paylaşılan bellek bloğuna gereksinim duyduğu için (referans sayımını saklamak için) ve her ne kadar aldatıcı bir şekilde işlenmemiş işaretlere göre biraz daha fazla yük olması gerektiğinden, silinen bir silme eklemenin büyük bir önemi yoktur. İşte. Öte yandan, hiçbir ek yükün olmaması için her yerde üst üste bindirilmek zorundadır ve her örnek onun delerini gömmek zorundadır, bu nedenle türün bir parçası yapmak, yapılması gereken doğal şeydir.

+0

Tür silinen delgeç nasıl btw denir? – WorldSEnder

+0

@WorldSEnder: Bu uygulamaya kadar, ama her zamanki yolu T * silinmesi için bunu uygulayan (devralır) templated sınıfa bir arayüz beton deleter kapsüllemek olmaktadır. Böylece, referans sayısı sıfıra ulaştığında, uygulama sanal yöntemi çağırır, bu çağrı, daha sonra beton deliciyi çağırmak için gömme sınıfına gönderilir. Std :: function ile aynı mekanizmadır. – Horstling

+1

'std :: function' ve muhtemelen 'shared_ptr' öğelerinin 'raw' alt düzey uygulamasının uygulamada daha hızlı olacağına dikkat edin, ancak birkaç tane std kütüphanesi bunları kullanır (google üzerinden 'mümkün olan en hızlı delegeler' bölümüne bakın). Vtable uygulaması, normal C++ gibi göründüğü kadarıyla anlaşılması en kolay olanıdır. – Yakk