Definitivamente un +1 en esto porque he visto a mucha gente equivocarse. Es una gran pregunta para hacer.
Twokats
Lea también el artículo relacionado. Esta pregunta se considera aquí desde el otro lado. Puede ser útil para comprender más sobre los contenedores auto_ptr y STL. stackoverflow.com/questions/8630552/…
movesemántica y unique_ptrfueron diseñados para evitar los problemas relacionados auto_ptr. En C ++ 03, el lenguaje no era lo suficientemente potente como para escribir una clase como auto_ptresa 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
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_ptrno 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.
También debe considerar los contenedores de puntero de impulso, si no necesita una propiedad compartida.
me22
44
unique_ptrtampoco permite la copia, por lo que ciertas operaciones STL no funcionarán correctamente a menos que puedan usar su semántica de movimiento.
Mike Weller
44
"Para superar esta limitación, debe usar 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_ptrinstancias son solo construibles por movimiento y asignables por movimiento. ¡Pero también lo son las auto_ptrinstancias! Como consecuencia, en C ++ 11 puede hacer con auto_ptrlo que puede hacer unique_ptr.
Marc van Leeuwen
@MarcvanLeeuwen a menos que resety releasecuando sea necesario
monstruo de trinquete
2
@ratchetfreak: Hmm, no entiendo. ¿Qué? "a menos que tú resety release", no veo cómo eso se aplica a nada en mi comentario. Tenga en cuenta que ambos auto_ptry unique_ptrtienen ambos métodos, y hacen lo mismo en ambos casos.
Marc van Leeuwen
66
La semántica de copia de auto_ptrno es compatible con los contenedores.
Específicamente, copiar uno auto_ptra otro no crea dos objetos iguales ya que uno ha perdido la propiedad del puntero.
Más específicamente, copiar un auto_ptrhace 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_ptrsen los contenedores.
Porque creo que en los casi dos años transcurridos, probablemente se ocupó del problema en cuestión.
Puppy
27
@DeadMG: sí, tienes razón. Pero ese no era mi propósito. Si alguien llega a este hilo en algún momento y quiere aprender sobre auto_ptresas cosas, estos enlaces serán útiles, estoy seguro.
Lazer
Hay muchos duplicados que son más recientes.
Cachorro
8
@DeadMG: esta pregunta no se cerró como duplicado y, por lo tanto, está abierta para la extensión. Lazer dijo lo que no se dijo antes aquí. Supongo que vino por casualidad.
Sebastian Mach
Las explicaciones en el segundo enlace, que analizan el problema después de llamar sort(), son más claras que todas las respuestas aquí.
Chaosink
17
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.
Pero, cuando usas unique_ptr, obtienes casi lo mismo, ya que solo un unique_ptr puede tener la propiedad del objeto.
Trazador
2
@Tracer, unique_ptrcomo 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.
underscore_d
4
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 tiempoRespuestas:
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 requisitoTome por ejemplo este código:
Para superar esta limitación, se debe utilizar el
std::unique_ptr
,std::shared_ptr
o losstd::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.fuente
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, lasunique_ptr
instancias son solo construibles por movimiento y asignables por movimiento. ¡Pero también lo son lasauto_ptr
instancias! Como consecuencia, en C ++ 11 puede hacer conauto_ptr
lo que puede hacerunique_ptr
.reset
yrelease
cuando sea necesarioreset
yrelease
", no veo cómo eso se aplica a nada en mi comentario. Tenga en cuenta que ambosauto_ptr
yunique_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 almacenaauto_ptrs
en los contenedores.fuente
Dos artículos súper excelentes sobre el tema:
fuente
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).
fuente
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.
fuente
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 deliberadamentestd::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 deauto_ptr
.El estándar C ++ 03 (ISO-IEC 14882-2003) dice en la cláusula 20.4.5, párrafo 3:
El estándar C ++ 11 (ISO-IEC 14882-2011) dice en el apéndice D.10.1 párrafo 3:
El estándar C ++ 14 (ISO-IEC 14882-2014) dice en el apéndice C.4.2 Anexo D: características de compatibilidad:
fuente