c++ - shared_ptr - unique_ptr-¿Mejora importante?
make_unique (5)
Cuando una colección se eliminará como efecto secundario de una excepción, llamará a los destructores de unique_ptr. No hay pérdida de memoria.
Sí, un contenedor de unique_ptr
satisfará esto.
unique_ptr no necesita ningún espacio adicional para el contador de referencia; por lo tanto su cuerpo debe ser exacto del mismo tamaño, como puntero envuelto
El tamaño de unique_ptr
está definido por la implementación. Si bien todas las implementaciones razonables de unique_ptr
usando su destructor predeterminado probablemente solo serán un puntero en tamaño, no hay garantía de esto en el estándar.
No estoy seguro, pero parece que esto permite mover grupos de unique_ptrs usando memmove () como operaciones (?),
Absolutamente no. unique_ptr
no es una clase trivial; por lo tanto, no puede ser memmove
. Incluso si lo fuera, no puedes simplemente memmove
, porque los destructores para los originales necesitan ser llamados. Tendría que ser un memmove
seguido por un memset
.
incluso si no es posible, el operador std :: move () permitirá mover cada objeto unique_ptr sin hacer las llamadas de par constructor / destructor.
También incorrecto. El movimiento no hace que los constructores y los destructores no sean llamados. Los unique_ptr
que están siendo destruidos deben ser destruidos ; Eso requiere una llamada a sus destructores. Del mismo modo, los nuevos unique_ptr
s deben tener sus constructores llamados; Así es como comienza la vida de un objeto.
No hay forma de evitar eso; Es como funciona C ++.
Sin embargo, eso no es lo que debería preocuparte. Honestamente, si está preocupado por una simple llamada de constructor / destructor, está en un código para el que debería estar optimizando a mano (y por lo tanto escribir su propio código para), o está optimizando prematuramente su código. Lo que importa no es si los constructores / destructores son llamados; lo que importa es qué tan rápido es el código resultante.
unique_ptr tendrá propiedad exclusiva de la memoria dada. No será posible ninguna pérdida de memoria accidental.
Si lo sera
Personalmente, yo diría que estás haciendo uno de los siguientes:
Ser excesivamente paranoico sobre copiar objetos. Esto es una prueba del hecho de que considera que poner una
shared_ptr
en un contenedor es una copia demasiado costosa. Esta es una enfermedad muy común entre los programadores de C ++. Eso no quiere decir que copiar sea siempre bueno o algo así, pero obsesionarse con copiar unshared_ptr
en un contenedor es ridículo fuera de circunstancias excepcionales.No es consciente de cómo usar correctamente la semántica de movimientos. Si sus objetos son caros para copiar, pero baratos para mover ... luego muévalos al contenedor. No hay razón para tener una dirección indirecta de puntero cuando sus objetos ya contienen direcciones indirectas de puntero. Simplemente use el movimiento con los objetos mismos, no
unique_ptr
s to objects.Sin tener en cuenta las alternativas. A saber, los contenedores de puntero de Boost . Parece que tienen todo lo que quieres. Poseen punteros a sus objetos, pero externamente tienen valor semántico en lugar de puntero semántico. Están a salvo de la excepción, y cualquier copia se realiza con punteros. No
unique_ptr
constructor / destructor "sobrecarga".
En el estándar actual de C ++, crear colecciones que cumplan las siguientes reglas es difícil, si no imposible:
- excepción de seguridad,
- Operaciones internas baratas (en contenedores STL reales: las operaciones son copias),
- Gestión automática de la memoria.
Para satisfacer (1), una colección no puede almacenar punteros en bruto. Para satisfacer (2), una colección debe almacenar punteros en bruto. Para satisfacer (3), una colección debe almacenar objetos por valor.
Conclusión: los tres elementos entran en conflicto entre sí.
El elemento (2) no se shared_ptr
cuando se shared_ptr
s porque cuando una colección necesitará mover un elemento, deberá realizar dos llamadas: a un constructor y a un destructor. No es posible realizar operaciones masivas de copiar / mover como memcpy()
.
¿Estoy unique_ptr
que el problema descrito se resolverá con unique_ptr
y std::move()
? Las colecciones que utilicen las herramientas podrán satisfacer las 3 condiciones:
- Cuando una colección se eliminará como efecto secundario de una excepción, llamará a los destructores de
unique_ptr
. No hay pérdida de memoria. -
unique_ptr
no necesita ningún espacio adicional para el contador de referencia; por lo tanto, su cuerpo debe ser exacto del mismo tamaño, como puntero envuelto, - No estoy seguro, pero parece que esto permite mover grupos de
unique_ptrs
usandomemmove()
como operaciones ( ? ), - incluso si no es posible, el operador
std::move()
permitirá mover cada objetounique_ptr
sin hacer las llamadas de par constructor / destructor.
-
-
unique_ptr
tendrá propiedad exclusiva de la memoria dada. No será posible ninguna pérdida de memoria accidental.
¿Es esto cierto? ¿Cuáles son otras ventajas de usar unique_ptr
?
Esta pregunta ilustra por qué me encanta el recolector de basura Boehm (libgc). Nunca es necesario copiar nada por razones de administración de memoria, y de hecho, la propiedad de la memoria ya no necesita ser mencionada como parte de las API. Tienes que comprar un poco más de RAM para obtener el mismo rendimiento de la CPU, pero ahorras cientos de horas de tiempo de los programadores. Tú decides.
Estoy totalmente de acuerdo. Por fin hay una forma natural de manejar los objetos asignados a un montón.
En respuesta a:
No estoy seguro, pero parece que esto permite mover grupos de
unique_ptr
s mediante el uso dememmove()
como operaciones,
hubo una proposal para permitir esto, pero no se ha incluido en el Estándar C ++ 11.
Parece que las tres condiciones que he enumerado en mi publicación son posibles de obtener mediante el uso de la biblioteca de Boost Pointer Container .
Sí, tiene usted razón. Solo agregaría que esto es posible gracias a las referencias de valor r.