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:
- Utilice
unique_ptr
cuando desee un único puntero a un objeto que será reclamado cuando se destruya ese único puntero. - 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.