¿Por qué está mal usarlo std::auto_ptr<>
con contenedores estándar?
El estándar C ++ dice que un elemento STL debe ser "construible por copia" y "asignable". En otras palabras, un elemento debe poder asignarse o copiarse y los dos elementos son lógicamente independientes. std::auto_ptr
no cumple este requisito
Tome por ejemplo este código:
class X
{
};
std::vector<std::auto_ptr<X> > vecX;
vecX.push_back(new X);
std::auto_ptr<X> pX = vecX[0]; // vecX[0] is assigned NULL.
Para superar esta limitación, se debe utilizar el std::unique_ptr
, std::shared_ptr
o los std::weak_ptr
punteros inteligentes o los equivalentes impulso si usted no tiene C ++ 11. Aquí está la documentación de la biblioteca de impulso para estos punteros inteligentes.
unique_ptr
tampoco permite la copia, por lo que ciertas operaciones STL no funcionarán correctamente a menos que puedan usar su semántica de movimiento.
std::unique_ptr
": esa plantilla de clase solo puede existir debido a la semántica de movimiento (su especificación requiere referencias de valor), por lo que requiere fundamentalmente C ++ 11. Sin embargo (y relacionado), el Estándar C ++ 11 ya no dice que un tipo de elemento STL debe ser "copiable-construible" y "asignable"; ser movible-construible y movible-asignable es suficiente. De hecho, las unique_ptr
instancias son solo construibles por movimiento y asignables por movimiento. ¡Pero también lo son las auto_ptr
instancias! Como consecuencia, en C ++ 11 puede hacer con auto_ptr
lo que puede hacer unique_ptr
.
reset
y release
cuando sea necesario
reset
y release
", no veo cómo eso se aplica a nada en mi comentario. Tenga en cuenta que ambos auto_ptr
y unique_ptr
tienen ambos métodos, y hacen lo mismo en ambos casos.
La semántica de copia de auto_ptr
no es compatible con los contenedores.
Específicamente, copiar uno auto_ptr
a otro no crea dos objetos iguales ya que uno ha perdido la propiedad del puntero.
Más específicamente, copiar un auto_ptr
hace que una de las copias suelte el puntero. Cuál de estos restos en el contenedor no está definido. Por lo tanto, puede perder aleatoriamente el acceso a los punteros si almacena auto_ptrs
en los contenedores.
Dos artículos súper excelentes sobre el tema:
auto_ptr
esas cosas, estos enlaces serán útiles, estoy seguro.
sort()
, son más claras que todas las respuestas aquí.
Los contenedores STL deben poder copiar los artículos que almacena en ellos, y están diseñados para esperar que el original y la copia sean equivalentes. Los objetos de puntero automático tienen un contrato completamente diferente, por lo que la copia crea una transferencia de propiedad. Esto significa que los contenedores de auto_ptr exhibirán un comportamiento extraño, dependiendo del uso.
Hay una descripción detallada de lo que puede salir mal en el artículo 8 de Effective STL (Scott Meyers) y también una descripción no tan detallada en el artículo 13 de Effective C ++ (Scott Meyers).
Los contenedores STL almacenan copias de artículos contenidos. Cuando se copia un auto_ptr, establece el antiguo ptr en nulo. Muchos métodos de contenedor se rompen por este comportamiento.
unique_ptr
como cualquier objeto C ++ 11 apropiado, solo puede transferir la propiedad de su recurso cuando se construye o se asigna el movimiento, asegurando que el programador debe pasar deliberadamente std::move(sourceObject)
un valor temporal o temporal, en lugar de pasar un valor l y de manera no intuitiva / impredecible tenerlo mutado por la asignación de copias ... que, como se enfatizó a fondo aquí, era un problema central de auto_ptr
.
El estándar C ++ 03 (ISO-IEC 14882-2003) dice en la cláusula 20.4.5, párrafo 3:
[...] [ Nota: [...] auto_ptr no cumple con los requisitos de CopyConstructible y Asignable para elementos del contenedor de la Biblioteca estándar y, por lo tanto, crear una instancia de un contenedor de la Biblioteca estándar con un auto_ptr da como resultado un comportamiento indefinido. - nota final ]
El estándar C ++ 11 (ISO-IEC 14882-2011) dice en el apéndice D.10.1 párrafo 3:
[...] Nota: [...] las instancias de auto_ptr cumplen los requisitos de MoveConstructible y MoveAssignable, pero no cumplen los requisitos de CopyConstructible y CopyAssignable. - nota final]
El estándar C ++ 14 (ISO-IEC 14882-2014) dice en el apéndice C.4.2 Anexo D: características de compatibilidad:
Cambio : las plantillas de clase auto_ptr, unary_function y binary_function, las plantillas de función random_shuffle y las plantillas de función (y sus tipos de retorno) ptr_fun, mem_fun, mem_fun_ref, bind1st y bind2nd no están definidas.
Justificación : Reemplazada por nuevas características.
Efecto sobre la característica original : el código válido de C ++ 2014 que usa estas plantillas de clase y plantillas de función puede fallar al compilarse en esta Norma Internacional.
move
semántica yunique_ptr
fueron diseñados para evitar los problemas relacionadosauto_ptr
. En C ++ 03, el lenguaje no era lo suficientemente potente como para escribir una clase comoauto_ptr
esa que se comporta de manera correcta y segura en todos los escenarios, ya que el compilador y el lenguaje no podían distinguir los valores l y r, por lo que se usaron algunos "hacks" para obtener el comportamiento deseado la mayor parte del tiempo