weak_ptr unique_ptr smart shared_ptr pointer example create c++ c++11 std shared-ptr unique-ptr

c++ - smart - ¿Por qué unique_ptr toma dos parámetros de plantilla cuando shared_ptr solo toma uno?



unique_ptr c++ (2)

Ambos unique_ptr y shared_ptr aceptan un destructor personalizado para llamar al objeto que poseen. Pero en el caso de unique_ptr , el destructor se pasa como un parámetro de plantilla de la clase , mientras que el tipo de destructor personalizado de shared_ptr se debe especificar como un parámetro de plantilla del constructor .

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

y

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

No puedo ver por qué tanta diferencia. ¿Qué requiere eso?


Los punteros compartidos de diferentes tipos pueden compartir la propiedad del mismo objeto . Ver sobrecarga (8) de std::shared_ptr::shared_ptr . Los punteros únicos no necesitan este mecanismo, ya que no comparten .

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

Si no escribió el borrado, no podría usar dicho shared_ptr<T, Y_Deleter> como shared_ptr<T> , lo que básicamente lo haría inútil.

¿Por qué querrías tal sobrecarga?

Considerar

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

Si desea mantener vivo el Container , mientras usa el Member , puede hacer

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

y solo tiene que aferrarse a pMember (tal vez ponerlo en std::vector<std::shared_ptr<Member>> )

O alternativamente, usando sobrecarga (9)

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

Puedes tener intercambio polimórfico

struct Base {}; struct Derived : Base {}; void operate_on_base(std::shared_ptr<Base>); std::shared_ptr<Derived> pDerived = /* something*/ operate_on_base(pDerived);


Si proporciona el eliminador como argumento de plantilla (como en unique_ptr ), es parte del tipo y no necesita almacenar nada adicional en los objetos de este tipo. Si el delegado se pasa como argumento del constructor (como en shared_ptr ), debe almacenarlo en el objeto. Este es el costo de la flexibilidad adicional, ya que puede usar diferentes eliminadores para los objetos del mismo tipo.

Supongo que esta es la razón: se supone que unique_ptr es un objeto muy liviano con cero gastos generales. El almacenamiento de los eliminadores con cada unique_ptr podría duplicar su tamaño. Debido a eso, la gente usaría buenos punteros crudos en su lugar, lo que sería incorrecto.

Por otro lado, shared_ptr no es tan liviano, ya que necesita almacenar el recuento de referencias, por lo que almacenar un eliminador personalizado también parece un buen intercambio.