2010-09-13 13 views
64

Ho sentito dire che auto_ptr è deprecato in C++ 11. Qual è la ragione di questo?Perché auto_ptr è deprecato?

Inoltre mi piacerebbe sapere la differenza tra auto_ptr e shared_ptr.

+0

Possibile duplicato (http://stackoverflow.com/questions/2404115/is-auto-ptr-deprecated) – malat

risposta

68

La sostituzione diretta per auto_ptr (o la cosa più vicina ad uno comunque) è unique_ptr. Per quanto riguarda il "problema", è piuttosto semplice: auto_ptr trasferisce la proprietà quando viene assegnata. unique_ptr trasferisce anche la proprietà, ma grazie alla codifica della semantica del movimento e alla magia dei riferimenti rvalue, può farlo in modo notevolmente più naturale. Inoltre "si adatta" al resto della libreria standard in modo considerevolmente migliore (anche se, in tutta onestà, parte di ciò è dovuto al fatto che il resto della libreria cambia per adattarsi alla semantica del movimento invece di richiedere sempre la copia).

Il cambiamento di nome è anche (IMO) un benvenuto uno - auto_ptr in realtà non vi dice molto su quello che si tenta di automatizzare, mentre unique_ptr è una descrizione abbastanza ragionevole (se terso) di ciò che è previsto.

+21

Solo una nota sul 'auto_ptr' nome [è Auto \ _ptr deprecato?]: Auto suggerisce automatico come nella variabile automatica e fa riferimento a una cosa che "auto_ptr' fa: distrugge la risorsa gestita nel suo distruttore (quando esce dal campo di applicazione). –

+12

Ulteriori informazioni: Ecco la spiegazione ufficiale per la deprecazione di '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 documento interessante! è strano nel senso che se std :: sort() ha una specializzazione per std :: unique_ptr per usare la semantica del movimento come necessario. Mi chiedo perché std :: sort() non possa essere specializzato per std :: auto_ptr per correggere il problema di copia menzionato nel doc. Grazie in anticipo. – Hei

19

shared_ptr possono essere stoccati all'interno di contenitori. auto_ptr no.

BTW unique_ptr è davvero il auto_ptr sostituzione diretta, combina le migliori caratteristiche di entrambi std::auto_ptr e boost::scoped_ptr.

28

Ho trovato le risposte esistenti grandiose, ma dal PoV dei puntatori. IMO, una risposta ideale dovrebbe avere la risposta prospettica dell'utente/programmatore.

Per prima cosa (come sottolineato da Jerry Coffin nella sua risposta)

  • auto_ptr potrebbe essere sostituito da shared_ptr o unique_ptr a seconda della situazione

shared_ptr: Se siete preoccupati per la liberazione di risorsa/memoria E se si dispone di più di una funzione che potrebbe utilizzare l'oggetto AT-DIFFERENT volte, quindi andare con shared_ptr.

Da DIFFERENT-Times, pensare a una situazione in cui l'oggetto-ptr è memorizzato in più strutture dati e successivamente acceduto. Più thread, ovviamente, è un altro esempio.

unique_ptr: Se tutto ciò che ti interessa è liberare memoria, e l'accesso all'oggetto è SEQUENTIAL, quindi vai a unique_ptr.

Per SEQUENTIAL, voglio dire, in qualsiasi punto l'accesso sarà accessibile da un contesto. Per esempio. un oggetto che è stato creato e utilizzato immediatamente dopo la creazione dal creatore. Dopo la creazione, l'oggetto viene memorizzato nella struttura dati FIRST. Quindi, l'oggetto viene distrutto dopo la struttura dati ONE o spostato nella struttura dati SECONDO.

Da questa riga, farò riferimento a shared/unique _ptr come puntatori intelligenti. (auto_ptr è anche smart-pointer BUT a causa di difetti nella sua progettazione, per cui sono deprecati, e che penso indicherò nelle righe successive, non dovrebbero essere raggruppati con smart-pointer.)

ragione più importante per spiegare perché auto_ptr è stata sconsigliata a favore di smart-pointer è assegnazione semantica Se non fosse stato per questo motivo, avrebbe aggiunto tutte le nuove chicche della semantica move al auto_ptr invece di deprecarlo. Dato che la semantica del compito era la caratteristica più sgradita, volevano che quella funzione andasse via, ma dal momento che c'è del codice scritto che usa quella semantica, (che il comitato degli standard non può cambiare), hanno dovuto lasciare andare auto_ptr, invece di modificandolo.

Dal link: http://www.cplusplus.com/reference/memory/unique_ptr/operator=/

Tipo di assegnazioni supportato da unqiue_ptr

  • assegnazione mossa (1)
  • assegnare puntatore nullo (2) Assegnazione
  • tipo pressofuso (3)
  • copia assegnazione (cancellata!) (4)

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

Tipo di assegnazioni supportate da auto_ptr

  • assegnamento per copia (4) colpevole

Ora venendo al motivo per cui l'assegnazione di copia era così antipatico, ho questa teoria:

  1. Non tutti i programmatori leggere libri o standard
  2. auto_ptr sulla faccia di esso, promette la proprietà dell'oggetto
  3. il little-* (gioco di parole), la clausola del auto_ptr, che non viene letta da tutti i programmatori, consente, l'assegnazione di un auto_ptr a un altro, e trasferisce la proprietà.
  4. La ricerca ha dimostrato che questo comportamento è inteso per 3,1415926535% di tutti gli usi e non è consentito in altri casi.

Il comportamento involontario è davvero sgradito e quindi l'antipatia per l'auto_ptr.

(Per il 3,1415926536% di programmatori che intenzionalmente vogliono trasferire la proprietà C++ 11 ha dato loro std :: move(), che ha reso chiara la loro intenzione per tutti gli stagisti che leggeranno e manterranno il codice .)

+1

Dato che ** non ** mai ** desidera due valori 'auto_ptr' che puntano allo stesso oggetto (dato che non danno la proprietà condivisa, il primo a morire lascerà l'altro con un'eredità letale, questo vale anche per' unique_ptr 'utilizzo), puoi suggerire _what was_ intended in quei restanti 96,8584073465% di tutti gli usi? –

+0

Non posso parlare per tutti loro, ma suppongo che, penserebbero * che la proprietà dell'oggetto venga * spostata * e NON solo duplicata, che è errata. –

+1

"Le ricerche sono state mostrate" :-) – deworde

6

ancora un altro assumere spiegare la differenza ....

Funzionalmente, C++ 11 del std::unique_ptr è "fisso" std::auto_ptr: entrambi sono adatti quando - in qualsiasi momento durante l'esecuzione - dovrebbe esserci un singolo proprietario di puntatore intelligente per un oggetto puntato.

La differenza cruciale è in copia-costruzione o l'assegnazione di un altro puntatore intelligente non-scadenza, indicata sulle => righe sotto:

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 

Sopra, ap3 tranquillamente "ruba" la proprietà di *ap, lasciando ap set a nullptr, e il problema è che può accadere troppo facilmente, senza che il programmatore abbia pensato alla sua sicurezza.

Ad esempio, se un class/struct ha un membro std::auto_ptr, quindi fare una copia di un'istanza sarà release il puntatore dall'istanza da copiare: questa è la semantica strani e pericolosamente fuorviante in quanto di solito la copia di qualcosa di non modificarlo. È facile per l'autore della classe/struct trascurare il rilascio del puntatore quando ragiona su invarianti e stato, e conseguentemente accidentalmente tenta di dereferenziare smart-pointer mentre è nullo, o semplicemente non ha ancora l'accesso/la proprietà previsti dei dati puntati.

+0

auto_ptr tranquillamente "ruba" la proprietà +1 – camino

1

auto_ptr non può essere utilizzato nei contenitori STL perché ha un costruttore di copia che non soddisfa i requisiti del contenitore CopyConstructible. unique_ptr non implementa un costruttore di copie, quindi i contenitori utilizzano metodi alternativi. unique_ptr può essere utilizzato in contenitori ed è più veloce per gli algoritmi standard rispetto a 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 
Problemi correlati