2009-06-05 6 views
20

En el C real ++ estándar, creando colecciones que satisfacen reglas siguientes es difícil si no imposible:unique_ptr - ¿mejoría importante?

  1. seguridad excepción,
  2. operaciones de vuelos internos (en contenedores STL reales: las operaciones son copias),
  3. automática gestión de la memoria.

Para satisfacer (1), una colección no puede almacenar punteros sin procesar. Para satisfacer (2), una colección debe almacenar punteros sin procesar. Para satisfacer (3), una colección debe almacenar objetos por valor.

Conclusión: los tres elementos entran en conflicto entre sí.

El artículo (2) no se cumplirá cuando se usen shared_ptr s porque cuando una colección tendrá que mover un elemento, tendrá que hacer dos llamadas: a un constructor y a un destructor. No es posible realizar operaciones de copia/movimiento masivas, memcpy().

¿Es correcto que el problema descrito se resuelva por unique_ptr y std::move()? Colecciones que utilizan las herramientas serán capaces de satisfacer todas las 3 condiciones:

  1. Cuando se elimina una colección como un efecto secundario de una excepción, se llamará destructores unique_ptr 's. Sin pérdida de memoria
    • unique_ptr no necesita ningún espacio adicional para el contador de referencia; por lo tanto, su cuerpo debe ser exactamente el mismo tamaño, como puntero envuelto,
    • No estoy seguro, pero parece que esto permite mover grupos de unique_ptrs utilizando memmove() operaciones similares (?),
    • incluso si es no es posible, el operador std::move() permitirá mover cada objeto unique_ptr sin realizar las llamadas de par constructor/destructor.
  2. unique_ptr tendrán la propiedad exclusiva de la memoria dada. No habrá pérdidas de memoria accidentales.

¿Es esto verdad? ¿Cuáles son otras ventajas de usar unique_ptr?

+6

Si yopu desea escribir un blog, siéntase libre de hacerlo, pero no aquí. –

+3

@Neil: Esta es una pregunta concreta, el problema es que tuve que incluir muchos antecedentes. Es * útil *, por ejemplo, la respuesta de James Hopkin, que las operaciones de Memcopy() no se incluyeron en el borrador. ¿Cómo más se suponía que iba a preguntar sobre eso? Sin el fondo? ¡Nadie lo entendería! –

+2

Quizás se hubiera preguntado mejor como '¿Cuáles son las ventajas de unique_ptr'. Siempre puedes responder tu propia pregunta. –

Respuesta

6

Estoy totalmente de acuerdo. Por fin hay una forma natural de manejar los objetos asignados en el montón.

En respuesta a:

No estoy seguro, pero parece que esto permite mover grupos de unique_ptr s utilizando memmove() operaciones similares,

había un proposal para permitir que este , pero no ha llegado al estándar C++ 11.

2

Sí, tienes razón. Solo agregaría que esto es posible gracias a las referencias de valor r.

0

Esta pregunta illlustrates por eso quiero tanto la Boehm garbage collector (libgc). Nunca hay necesidad de 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.

+9

Los tiempos de pausa en Boehm GC son horribles. Incluso Java es mejor. – Zifre

+0

Creo que la idea aquí es mantenerse alejado de los recolectores de basura. –

2

Cuando una colección se eliminará como efecto secundario de una excepción, se llamarán destructores de unique_ptr. Sin 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 exactamente del mismo tamaño, como el puntero envuelto

unique_ptr El tamaño está definido por la implementación. Mientras que todas las implementaciones razonables de unique_ptr utilizando su destructor por defecto es probable que sólo sea un puntero de tamaño, no hay ninguna garantía de de esto en la norma.

No estoy seguro, pero parece que esto permite mover grupos de unique_ptrs utilizando memmove() operaciones similares (?),

Por supuesto que no

. unique_ptr no es una clase trivial; por lo tanto, no puede ser memmove d alrededor. Incluso si lo fuera, no puede simplemente llamarlos memmove, porque los destructores para los originales deben llamarse. Tendría que ser un memmove seguido de un memset.

aunque no sea posible, el operador std :: move() permitirá mover cada objeto unique_ptr sin realizar las llamadas de par constructor/destructor.

también incorrecta. El movimiento no hace que los constructores y los destructores no sean llamados. Los unique_ptr que se destruyen deben ser destruidos; eso requiere una llamada a sus destructores. Del mismo modo, los nuevos unique_ptr s necesitan tener sus constructores llamados; así es como comienza la vida de un objeto.

No hay que evitar; así es como funciona C++.

Sin embargo, eso no es lo que debe estar preocupado. Honestamente, si le preocupa una simple llamada de constructor/destructor, o bien tiene un código que debe optimizar manualmente (y por lo tanto escribir su propio código), o está optimizando prematuramente su código. Lo que importa no es si se llaman constructores/destructores; lo que importa es qué tan rápido es el código resultante.

unique_ptr tendrá la propiedad exclusiva de la memoria dada. No habrá pérdidas de memoria accidentales.

Sí, lo hará.

En lo personal, yo diría que está haciendo uno de los siguientes:

  • Ser excesivamente paranoico sobre la copia de objetos. Esto es evidencia por el hecho de que considera poner un shared_ptr en un contenedor es demasiado costoso de una copia. Esta es una enfermedad muy común entre los programadores de C++. Eso no quiere decir que copiar siempre sea bueno o algo así, pero obsesionarse con copiar un shared_ptr en un contenedor es ridículo fuera de circunstancias excepcionales.

  • No se sabe cómo usar correctamente la semántica de movimiento. Si sus objetos son caros de copiar pero baratos de mover ... luego muévalos al contenedor. No hay ninguna razón para tener un indirecto de puntero cuando sus objetos ya contienen direcciones indirectas de puntero. Solo use el movimiento con los objetos en sí, no con unique_ptr s a los objetos.

  • Sin tener en cuenta las alternativas. A saber, Boost's pointer containers. Parece que tienen todo lo que quieres. Poseen punteros a sus objetos, pero externamente tienen semántica de valores en lugar de semántica de punteros. Son una excepción segura, y cualquier copia ocurre con punteros. No unique_ptr constructor/destructor "overhead".