unique_ptr smart shared_ptr punteros inteligentes example c++ pointers c++11 shared-ptr unique-ptr

c++ - smart - Diferencias entre unique_ptr y shared_ptr



shared_ptr example (4)

Posibles duplicados:
pimpl: shared_ptr o unique_ptr
indicadores inteligentes (boost) explicados

¿Alguien podría explicar las diferencias entre shared_ptr y unique_ptr?


Al unique_ptr un puntero en unique_ptr no puede tener varias copias de unique_ptr . shared_ptr contiene un contador de referencia que cuenta el número de copias del puntero almacenado. Cada vez que se copia un shared_ptr , este contador se incrementa. Cada vez que se shared_ptr un shared_ptr , este contador disminuye. Cuando este contador llega a 0, entonces el objeto almacenado se destruye.


Ambas clases son punteros inteligentes, lo que significa que automáticamente (en la mayoría de los casos) desasignarán el objeto al que apuntan cuando ese objeto ya no se puede referenciar. La diferencia entre los dos es cuántos punteros diferentes de cada tipo pueden referirse a un recurso.

Cuando se utiliza unique_ptr , puede haber como máximo un unique_ptr apuntando a cualquier recurso. Cuando se destruye ese unique_ptr , el recurso se unique_ptr automáticamente. Como solo puede haber un unique_ptr para cualquier recurso, cualquier intento de hacer una copia de un unique_ptr causará un error en tiempo de compilación. Por ejemplo, este código es ilegal:

unique_ptr<T> myPtr(new T); // Okay unique_ptr<T> myOtherPtr = myPtr; // Error: Can''t copy unique_ptr

Sin embargo, unique_ptr se puede mover usando la nueva semántica de movimiento:

unique_ptr<T> myPtr(new T); // Okay unique_ptr<T> myOtherPtr = std::move(myPtr); // Okay, resource now stored in myOtherPtr

Del mismo modo, puedes hacer algo como esto:

unique_ptr<T> MyFunction() { unique_ptr<T> myPtr(/* ... */); /* ... */ return myPtr; }

Esta expresión idiomática significa "Te estoy devolviendo un recurso administrado. Si no capturas explícitamente el valor devuelto, entonces el recurso se limpiará. Si lo haces, entonces ahora tienes la propiedad exclusiva de ese recurso". De esta manera, puedes pensar en unique_ptr como un reemplazo mejor y más seguro para auto_ptr .

shared_ptr , por otro lado, permite punteros múltiples para apuntar a un recurso dado. Cuando se destruye la última shared_ptr de un recurso, el recurso será desasignado. Por ejemplo, este código es perfectamente legal:

shared_ptr<T> myPtr(new T); // Okay shared_ptr<T> myOtherPtr = myPtr; // Sure! Now have two pointers to the resource.

Internamente, shared_ptr utiliza el recuento de referencias para realizar un seguimiento de cuántos punteros se refieren a un recurso, por lo que debe tener cuidado de no introducir ningún ciclo de referencia.

En breve:

  1. Utilice unique_ptr cuando desee un único puntero a un objeto que será reclamado cuando se destruya ese único puntero.
  2. Use shared_ptr cuando quiera múltiples punteros al mismo recurso.

¡Espero que esto ayude!


unique_ptr es el puntero inteligente ligero de elección si solo tienes un objeto dinámico en alguna parte para el que un consumidor tiene la responsabilidad única (y por lo tanto "única"), tal vez una clase contenedora que necesita mantener algún objeto dinámicamente asignado. unique_ptr tiene muy poca sobrecarga. No se puede copiar, pero se puede mover. Su tipo es template <typename D, typename Deleter> class unique_ptr; , entonces depende de dos parámetros de plantilla.

unique_ptr es también lo que auto_ptr quería ser en el viejo C ++, pero no pudo debido a las limitaciones de ese idioma.

shared_ptr por otro lado es un animal muy diferente. La diferencia obvia es que puede hacer que muchos consumidores compartan la responsabilidad de un objeto dinámico (por lo tanto, "compartido"), y el objeto solo se destruirá cuando todos los punteros compartidos se hayan eliminado. Además, puede observar punteros débiles que se informarán de forma inteligente si el puntero compartido que están siguiendo ha desaparecido.

Internamente, shared_ptr tiene mucho más en shared_ptr : hay un recuento de referencias, que se actualiza atómicamente para permitir el uso en el código concurrente. Además, existe una gran cantidad de asignaciones, una para un "bloque de control de referencia" de contabilidad interno y otra (a menudo) para el objeto miembro real.

Pero hay otra gran diferencia: el tipo de punteros compartidos siempre es la template <typename T> class shared_ptr; , y esto a pesar del hecho de que puede inicializarlo con modificadores personalizados y con asignadores personalizados. El eliminador y el asignador se rastrean mediante el borrado de tipos y el despacho virtual de funciones, lo que aumenta el peso interno de la clase, pero tiene la enorme ventaja de que todos los tipos de punteros compartidos de tipo T son compatibles, sin importar los detalles de borrado y asignación. ¡Así expresan realmente el concepto de "responsabilidad compartida por T " sin cargar al consumidor con los detalles!

Tanto shared_ptr como unique_ptr están diseñados para pasar por valor (con el requisito de movilidad obvio para el puntero único). Tampoco deberían preocuparle los gastos generales, ya que su poder es realmente asombroso, pero si tiene otra opción, prefiera unique_ptr , y solo use shared_ptr si realmente necesita responsabilidad compartida.


unique_ptr
es un puntero inteligente que posee un objeto exclusivamente.

shared_ptr
es un puntero inteligente para propiedad compartida. Es copyable y movable . Varias instancias de puntero inteligente pueden ser propietarias del mismo recurso. Tan pronto como el último puntero inteligente que posee el recurso salga del alcance, el recurso será liberado.