2010-09-13 24 views
64

Escuché que auto_ptr está en desuso en C++ 11. ¿Cuál es la razón para esto?¿Por qué auto_ptr está en desuso?

También me gustaría saber la diferencia entre auto_ptr y shared_ptr.

+0

Posible duplicado de (http://stackoverflow.com/questions/2404115/is-auto-ptr-deprecated) – malat

Respuesta

68

El reemplazo directo para 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 de rvalue, puede hacerlo de forma mucho más natural. También "encaja" con el resto de la biblioteca estándar considerablemente mejor (aunque, para ser justos, parte de eso se debe a que el resto de la biblioteca cambia para adaptarse a la semántica de movimientos en lugar de requerir siempre la copia).

El cambio en el nombre también es (IMO) bienvenido - auto_ptr realmente no dice mucho sobre lo que intenta automatizar, mientras que unique_ptr es una descripción bastante razonable (aunque concisa) de lo que se proporciona.

+21

Sólo una nota en la 'auto_ptr' nombre [es Auto \ _ptr obsoleto?]: Auto sugiere automático como en la variable automática, y se refiere a una cosa que hace 'auto_ptr': destruir el recurso administrado en su destructor (cuando sale del alcance). –

+12

Más información: Aquí está la razón oficial para desaprobar 'auto_ptr': http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1856.html#20.4.5%20-% 20Class% 20template% 20auto_ptr –

+0

@HowardHinnant doc interesante! es extraño en cierto sentido que si std :: sort() tiene una especialización para std :: unique_ptr para usar la semántica de movimiento según sea necesario. Me pregunto por qué std :: sort() no puede ser especializado para std :: auto_ptr para corregir el problema de copia mencionado en el documento. Gracias por adelantado. – Hei

19

shared_ptr se pueden almacenar dentro de los contenedores. auto_ptr no puede.

Por cierto unique_ptr es realmente el auto_ptr reemplazo directo, que combina las mejores características de ambos std::auto_ptr y boost::scoped_ptr.

28

Encontré las respuestas existentes geniales, pero desde el PoV de los punteros. IMO, una respuesta ideal debe tener la respuesta de perspectiva del usuario/programador.

Primero lo primero (como se ha señalado por Jerry ataúd en su respuesta)

  • auto_ptr podría ser sustituido por shared_ptr o unique_ptr dependiendo de la situación

shared_ptr: Si usted está preocupado por la liberación de recurso/memoria Y si tiene más de una función que podría usar el objeto AT-DIFFERENT veces, entonces vaya con shared_ptr.

POR DIFERENTES veces, piense en una situación donde el objeto-ptr se almacena en una estructura de datos múltiple y luego se accede a él. Múltiples hilos, por supuesto, es otro ejemplo.

unique_ptr: Si lo único que le preocupa es liberar memoria, y el acceso al objeto es SECUENCIAL, entonces vaya a unique_ptr.

Por SECUENCIAL, quiero decir, en cualquier punto se accederá a un objeto desde un contexto. P.ej. 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 FIRST data-structure. Entonces, o bien el objeto se destruye después de la estructura de datos ONE o se mueve a SECOND data-structure.

De esta línea, recomendaré _ptr compartida/única como punteros inteligentes. (auto_ptr también es un puntero inteligente PERO debido a defectos en su diseño, por lo que están en desuso, y que creo que señalaré en las siguientes líneas, no deberían agruparse con puntero inteligente.)

sola razón más importante de por qué auto_ptr está desfasada y en favor de smart-puntero es asignación semántica Si no fuera por esa razón, se habría añadido todos los nuevos objetos valiosos de la semántica movimiento a auto_ptr en lugar de desaprobarlo. Como la semántica de asignación era la característica más desagradable, querían que esa característica desapareciera, pero dado que hay un código escrito que usa esa semántica (que el comité de normas no puede cambiar), tuvieron que soltar auto_ptr, en lugar de modificándolo.

Desde el enlace: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/

Tipo de asignaciones apoyado por unqiue_ptr

  • asignación de movimiento (1)
  • asignar puntero nulo (2) asignación
  • tipo-cast (3)
  • asignación de copia (¡eliminado!) (4)

Desde: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/

tipo de tareas con el apoyo de auto_ptr

  • de asignación de copia (4) culpable

Ahora que se acerca a la razón por la asignación copia en sí era tan desagradable, tengo esta teoría:

  1. No todos los programadores leen libros o normas
  2. auto_ptr en la cara de ella, promete que la propiedad del objeto
  3. la poco- * (juego de palabras), la cláusula de la auto_ptr, que no se lee por todos los programadores, permite la asignación de un auto_ptr a otro y transfiere la propiedad.
  4. La investigación ha demostrado que este comportamiento está destinado al 3.1415926535% del uso total y no intencional en otros casos.

El comportamiento no deseado realmente no le gusta y, por lo tanto, no le gusta el auto_ptr.

(Para el 3.1415926536% de los programadores que intencionalmente quieren transferir la propiedad C++ 11 les dio std :: move(), lo que hizo su intención clara para todos los internos que van a leer y mantener el código .)

+1

Dado que ** nunca ** quiere dos valores 'auto_ptr' que apunten al mismo objeto (dado que no otorgan propiedad compartida, el primero en morir dejará al otro con un legado letal; esto también es cierto para' unique_ptr 'uso), ¿puedes sugerir _ lo que fue_ en el 96.8584073465% restante de todos los usos? –

+0

No puedo hablar por todos ellos, pero supongo que ellos * pensarían * que la propiedad del objeto está * movida * y NO está duplicada, lo que es erróneo. –

+1

"La investigación ha demostrado" :-) – deworde

6

Sin embargo, otra toma en la explicación de la diferencia ....

Funcionalmente, C++ de 11 std::unique_ptr es el "fijo" std::auto_ptr: ambos son adecuados cuando - en cualquier punto en el tiempo durante la ejecución - debe haber un único propietario de puntero inteligente para un objeto apuntado.

La diferencia fundamental está en la copia de la construcción o la asignación de otro puntero inteligente no-expirar, se muestra en los => líneas más abajo:

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 silencio "roba" la propiedad de *ap, dejando ap conjunto a un nullptr, y el problema es que puede suceder muy fácilmente, sin que el programador haya pensado en su seguridad.

Por ejemplo, si un class/struct tiene un miembro std::auto_ptr, a continuación, hacer una copia de una instancia se release el puntero de la instancia que se está copiado: eso es la semántica extraños y peligrosamente confusos como suele copiar algo no modificarlo. Es fácil para el autor de la clase/estructura pasar por alto el lanzamiento del puntero al razonar sobre invariantes y el estado, y consecuentemente intentar accidentalmente desreferenciar el puntero inteligente mientras está nulo, o simplemente no tener el acceso/propiedad esperado de los datos apuntados.

+0

auto_ptr silenciosamente "roba" la propiedad +1 – camino

1

auto_ptr no se puede utilizar en contenedores STL porque tiene un constructor de copia que no cumple los requisitos del contenedor CopyConstructible. unique_ptr no implementa un constructor de copia, por lo que los contenedores utilizan métodos alternativos. unique_ptr se puede usar en contenedores y es más rápido para algoritmos std 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 
Cuestiones relacionadas