c++ - unique_ptr - weak_ptr from shared_ptr




Perché unique_ptr richiede due parametri del modello quando shared_ptr ne prende uno solo? (2)

Sia unique_ptr che shared_ptr accettano un distruttore personalizzato per chiamare l'oggetto di loro proprietà. Ma nel caso di unique_ptr , il distruttore viene passato come parametro del modello della classe , mentre il tipo di distruttore personalizzato di shared_ptr deve essere specificato come parametro del modello del costruttore .

template <class T, class D = default_delete<T>> 
class unique_ptr
{
    unique_ptr(T*, D&); //simplified
    ...
};

e

template<class T>
class shared_ptr
{
    template<typename D>
    shared_ptr(T*, D); //simplified
    ...
};

Non riesco a capire perché tale differenza. Cosa lo richiede?


Puntatori condivisi di tipi diversi possono condividere la proprietà dello stesso oggetto . Vedi overload (8) di std::shared_ptr::shared_ptr . I puntatori unici non hanno bisogno di un tale meccanismo, in quanto non condividono .

template< class Y > 
shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) noexcept;

Se non si digita il cancellatore del testo, non si sarebbe in grado di utilizzare tale shared_ptr<T, Y_Deleter> come shared_ptr<T> , il che lo renderebbe sostanzialmente inutile.

Perché vuoi un tale sovraccarico?

Prendere in considerazione

struct Member {};
struct Container { Member member };

Se vuoi mantenere vivo il Container , mentre usi il Member , puoi farlo

std::shared_ptr<Container> pContainer = /* something */
std::shared_ptr<Member> pMember(pContainer, &pContainer->member);

e devo solo tenere premuto pMember (magari inserirlo in un file std::vector<std::shared_ptr<Member>> )

In alternativa, usando il sovraccarico (9)

template< class Y > 
shared_ptr( const shared_ptr<Y>& r ) noexcept; 
  // Only exists if Y* is implicitly convertible to T*

Puoi avere una condivisione polimorfica

struct Base {};
struct Derived : Base {};

void operate_on_base(std::shared_ptr<Base>);

std::shared_ptr<Derived> pDerived = /* something*/
operate_on_base(pDerived);

Se fornisci il deleter come argomento modello (come in unique_ptr ) fa parte del tipo e non è necessario memorizzare nulla di aggiuntivo negli oggetti di questo tipo. Se il deleter viene passato come argomento del costruttore (come in shared_ptr ) è necessario memorizzarlo nell'oggetto. Questo è il costo di una maggiore flessibilità, dal momento che è possibile utilizzare diversi deletatori per gli oggetti dello stesso tipo.

Immagino che questo sia il motivo: unique_ptr dovrebbe essere un oggetto molto leggero con zero overhead. Memorizzare i unique_ptr con ciascun unique_ptr potrebbe raddoppiare le loro dimensioni. Per questo motivo la gente userebbe invece dei buoni vecchi puntatori grezzi, il che sarebbe sbagliato.

D'altra parte, shared_ptr non è così leggero, dal momento che ha bisogno di memorizzare il conteggio dei riferimenti, quindi anche la memorizzazione di un deleter personalizzato sembra un buon compromesso.







unique-ptr