Escuché que auto_ptr
está siendo obsoleto en C ++ 11. ¿Cuál es la razón para esto?
También me gustaría saber la diferencia entre auto_ptr
y shared_ptr
.
Respuestas:
El reemplazo directo de auto_ptr
(o lo más parecido a uno de todos modos) es unique_ptr
. En lo que respecta al "problema", es bastante simple: auto_ptr
transfiere la propiedad cuando se asigna. unique_ptr
también transfiere la propiedad, pero gracias a la codificación de la semántica de movimientos y la magia de las referencias rvalue, puede hacerlo de forma considerablemente más natural. También "encaja" con el resto de la biblioteca estándar considerablemente mejor (aunque, para ser justos, algo de eso se debe a que el resto de la biblioteca cambió para adaptarse a la semántica de movimiento en lugar de requerir siempre copia).
El cambio de nombre también es (en mi opinión) bienvenido: en auto_ptr
realidad no le dice mucho sobre lo que intenta automatizar, mientras que unique_ptr
es una descripción bastante razonable (aunque concisa) de lo que se proporciona.
auto_ptr
nombre: auto sugiere automático como variable automática, y se refiere a una cosa que auto_ptr
hace: destruir el recurso administrado en su destructor (cuando sale del alcance).
auto_ptr
: open-std.org/jtc1/sc22/wg21/docs/papers/2005/…
std::sort
no tiene especialización en unique_ptr
. En cambio, se volvió a especificar para no copiar nunca. Así que auto_ptr
en realidad hace el trabajo con el moderno sort
. Pero el C ++ 98/03 sort
es solo un algoritmo de ejemplo aquí: cualquier algoritmo genérico (proporcionado por el estándar o escrito por el usuario) que asume que la sintaxis de copia tiene semántica de copia probablemente tendrá un error de tiempo de ejecución si se usa con auto_ptr
, porque auto_ptr
se mueve silenciosamente con sintaxis de copia . El problema es mucho más grande que solo sort
.
Encontré excelentes respuestas existentes, pero desde el punto de vista de los punteros. En mi opinión, una respuesta ideal debe tener la respuesta de perspectiva del usuario / programador.
Primero lo primero (como lo señaló Jerry Coffin en su respuesta)
shared_ptr: Si le preocupa la liberación de recursos / memoria Y si tiene más de una función que podría estar usando el objeto AT-DIFFERENT veces, vaya con shared_ptr.
Por DIFFERENT-Times, piense en una situación en la que el objeto-ptr se almacena en múltiples estructuras de datos y luego se accede a él. Varios hilos, por supuesto, es otro ejemplo.
unique_ptr: Si lo único que le preocupa es liberar memoria y el acceso al objeto es SECUENCIAL, elija unique_ptr.
Por SECUENCIAL, quiero decir, en cualquier punto se accederá al objeto desde un contexto. Por ejemplo, un objeto que fue creado y utilizado inmediatamente después de la creación por el creador. Después de la creación, el objeto se almacena en la PRIMERA estructura de datos. Luego, el objeto se destruye después de la UNA estructura de datos o se mueve a la SEGUNDA estructura de datos.
Desde esta línea, me referiré a _ptr compartido / único como punteros inteligentes. (auto_ptr también es un puntero inteligente, PERO debido a fallas en su diseño, por lo que están en desuso, y que creo que señalaré en las siguientes líneas, no deben agruparse con el puntero inteligente).
La única razón más importante de por qué auto_ptr se desaprobó en favor de smart-pointer es la semántica de asignación. Si no fuera por esa razón, habrían agregado todas las novedades de la semántica de movimiento a auto_ptr en lugar de desaprobarlo. Dado que la semántica de asignación era la característica más desagradable, querían que esa característica desapareciera, pero como hay código escrito que usa esa semántica (que el comité de estándares no puede cambiar), tuvieron que dejar de lado auto_ptr, en lugar de modificarlo.
Desde el enlace: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/
Tipo de asignaciones admitidas por unqiue_ptr
De: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/
Tipo de asignaciones admitidas por auto_ptr
Ahora, llegando a la razón por la que la asignación de copia en sí misma no le gustó tanto, tengo esta teoría:
El comportamiento no deseado es realmente desagradable y, por lo tanto, el desagrado por auto_ptr.
(Para el 3.1415926536% de los programadores que intencionalmente quieren transferir la propiedad, C ++ 11 les dio std :: move (), lo que dejó en claro su intención para todos los pasantes que leerán y mantendrán el código).
auto_ptr
valores que apunten al mismo objeto (dado que no dan propiedad compartida, el primero en morir dejará al otro con una herencia letal; esto también es cierto para el unique_ptr
uso), ¿puede sugerir lo que se pretendía en los restantes 96.8584073465% de todo el uso?
*a=*b;
aquí solo el valor de b se copia en a. Espero que la propiedad de a y b siga perteneciendo a las mismas personas. Mencionaste que la propiedad será transferida. ¿Cómo sera?
auto_ptr
objeto en sí. La asignación a / desde su valor señalado no tiene efecto ni relevancia para la propiedad. Espero que no se sigue usando auto_ptr
?
Otra versión más para explicar la diferencia ...
Funcionalmente, C ++ 11 std::unique_ptr
es el "fijo" std::auto_ptr
: ambos son adecuados cuando, en cualquier momento durante la ejecución, debería haber un único propietario de puntero inteligente para un objeto apuntado.
La diferencia crucial está en la construcción de copias o la asignación de otro puntero inteligente que no expira, que se muestra en las =>
líneas siguientes:
std::auto_ptr<T> ap(...);
std::auto_ptr<T> ap2(get_ap_to_T()); // take expiring ownership
=> std::auto_ptr<T> ap3(ap); // take un-expiring ownership ala ap3(ap.release());
ap->xyz; // oops... can still try to use ap, expecting it to be non-NULL
std::unique_ptr<T> up(...);
std::unique_ptr<T> up2(get_up_to_T()); // take expiring ownership
=> std::unique_ptr<T> up3(up); // COMPILE ERROR: can't take un-expiring ownership
=> std::unique_ptr<T> up4(std::move(up)); // EXPLICIT code allowed
=> std::unique_ptr<T> up4(up.release()); // EXPLICIT code allowed
Arriba, ap3
silenciosamente "roba" la propiedad de *ap
, dejándolo ap
configurado en a nullptr
, y el problema es que puede suceder con demasiada facilidad, sin que el programador haya pensado en su seguridad.
Por ejemplo, si un class
/ struct
tiene un std::auto_ptr
miembro, al hacer una copia de una instancia aparecerá release
el puntero de la instancia que se está copiando: esa es una semántica extraña y peligrosamente confusa, ya que normalmente copiar algo no lo modifica. Es fácil para el autor de la clase / estructura pasar por alto la liberación del puntero cuando razona sobre invariantes y estados y, en consecuencia, intenta accidentalmente desreferenciar el puntero inteligente mientras es nulo, o simplemente no tiene el acceso / propiedad esperado de los datos apuntados.
auto_ptr no se puede usar en contenedores STL porque tiene un constructor de copia que no cumple con los requisitos del contenedor CopyConstructible . unique_ptr no implementa un constructor de copia, por lo que los contenedores usan métodos alternativos. unique_ptr se puede usar en contenedores y es más rápido para los algoritmos estándar que shared_ptr.
#include <iostream>
#include <type_traits>
#include <vector>
#include <memory>
using namespace std;
int main() {
cout << boolalpha;
cout << "is_copy_constructible:" << endl;
cout << "auto_ptr: " << is_copy_constructible< auto_ptr<int> >::value << endl;
cout << "unique_ptr: " << is_copy_constructible< unique_ptr<int> >::value << endl;
cout << "shared_ptr: " << is_copy_constructible< shared_ptr<int> >::value << endl;
vector<int> i_v;
i_v.push_back(1);
cout << "i_v=" << i_v[0] << endl;
vector<int> i_v2=i_v;
cout << "i_v2=" << i_v2[0] << endl;
vector< unique_ptr<int> > u_v;
u_v.push_back(unique_ptr<int>(new int(2)));
cout << "u_v=" << *u_v[0] << endl;
//vector< unique_ptr<int> > u_v2=u_v; //will not compile, need is_copy_constructible == true
vector< unique_ptr<int> > u_v2 =std::move(u_v); // but can be moved
cout << "u_v2=" << *u_v2[0] << " length u_v: " <<u_v.size() << endl;
vector< shared_ptr<int> > s_v;
shared_ptr<int> s(new int(3));
s_v.push_back(s);
cout << "s_v=" << *s_v[0] << endl;
vector< shared_ptr<int> > s_v2=s_v;
cout << "s_v2=" << *s_v2[0] << endl;
vector< auto_ptr<int> > a_v; //USAGE ERROR
return 0;
}
>cxx test1.cpp -o test1
test1.cpp: In function âint main()â:
test1.cpp:33:11: warning: âauto_ptrâ is deprecated (declared at /apps/hermes/sw/gcc/gcc-4.8.5/include/c++/4.8.5/backward/auto_ptr.h:87) [-Wdeprecated-declarations]
vector< auto_ptr<int> > a_v; //USAGE ERROR
^
>./test1
is_copy_constructible:
auto_ptr: false
unique_ptr: false
shared_ptr: true
i_v=1
i_v2=1
u_v=2
s_v=3
s_v2=3