Ho sentito che auto_ptr
è stato deprecato in C ++ 11. Qual è la ragione di ciò?
Inoltre vorrei conoscere la differenza tra auto_ptr
e shared_ptr
.
Risposte:
La sostituzione diretta per auto_ptr
(o comunque la cosa più vicina a una) è 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 codificazione della semantica del movimento e alla magia dei riferimenti rvalue, può farlo in modo molto più naturale. Inoltre "si adatta" notevolmente al resto della libreria standard (anche se, in tutta onestà, parte di ciò è dovuto al fatto che il resto della libreria cambia per adattarsi alla semantica dello spostamento invece di richiedere sempre la copia).
Anche il cambio di nome (IMO) è gradito: in auto_ptr
realtà non ti dice molto su ciò che tenta di automatizzare, mentre unique_ptr
è una descrizione abbastanza ragionevole (se concisa) di ciò che viene fornito.
auto_ptr
nome: auto suggerisce automatico come nella variabile automatica, e si riferisce a una cosa che auto_ptr
fa: distruggere la risorsa gestita nel suo distruttore (quando esce dall'ambito).
auto_ptr
: open-std.org/jtc1/sc22/wg21/docs/papers/2005/…
std::sort
non ha una specializzazione per unique_ptr
. Invece è stato re-specificato di non copiare mai. Quindi funzionaauto_ptr
davvero con il moderno . Ma il C ++ 98/03 è solo un algoritmo di esempio qui: qualsiasi algoritmo generico (fornito dallo standard o scritto dall'utente) che presume che la sintassi della copia abbia la semantica della copia probabilmente avrà un errore di runtime se usato con , perché si muove silenziosamente con sintassi di copia . Il problema è molto più ampio del semplice . sort
sort
auto_ptr
auto_ptr
sort
Ho trovato ottime le risposte esistenti, 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)
shared_ptr: se sei preoccupato per la liberazione di risorse / memoria E se hai più di una funzione che potrebbe utilizzare l'oggetto AT-DIFFERENT volte, allora vai con shared_ptr.
Con DIFFERENT-Times, pensa a una situazione in cui l'oggetto-ptr è memorizzato in più strutture dati e successivamente vi si accede. Più thread, ovviamente, è un altro esempio.
unique_ptr: se tutto ciò che ti interessa è liberare memoria e l'accesso all'oggetto è SEQUENZIALE, scegli unique_ptr.
Con SEQUENZIALE, intendo, in qualsiasi punto si accederà all'oggetto da un contesto. Ad esempio un oggetto che è stato creato e utilizzato immediatamente dopo la creazione dal creatore. Dopo la creazione l'oggetto viene memorizzato nella PRIMA struttura dati. Quindi o l'oggetto viene distrutto dopo l'UNICA struttura dati o viene spostato nella SECONDA struttura dati.
Da questa riga, farò riferimento a shared / unique _ptr come smart-pointer. (auto_ptr è anche smart-pointer MA a causa di difetti nel suo design, per i quali sono stati deprecati, e che penso indicherò nelle prossime righe, non dovrebbero essere raggruppati con smart-pointer.)
L'unico motivo più importante per cui auto_ptr è stato deprecato a favore di smart-pointer è la semantica dell'assegnazione Se non fosse stato per questo motivo, avrebbero aggiunto tutte le nuove chicche della semantica di spostamento ad auto_ptr invece di deprecarlo. Dato che la semantica di assegnazione era la caratteristica più antipatica, volevano che quella caratteristica sparisse, ma poiché è stato scritto del codice 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 incarichi supportati da unqiue_ptr
Da: http://www.cplusplus.com/reference/memory/auto_ptr/operator=/
Tipo di incarichi supportati da auto_ptr
Ora arrivando al motivo per cui l'assegnazione della copia stessa era così antipatica, ho questa teoria:
Il comportamento non intenzionale è davvero antipatico e quindi l'antipatia per auto_ptr.
(Per il 3,1415926536% dei programmatori che vuole intenzionalmente trasferire la proprietà C ++ 11 ha dato loro std :: move (), che ha reso la loro intenzione chiarissima per tutti gli stagisti che leggeranno e manterranno il codice.)
auto_ptr
valori puntino allo stesso oggetto (dato che non danno la proprietà condivisa, il primo che muore lascerà l'altro con un'eredità letale; questo vale anche per l' unique_ptr
uso), puoi suggerire cosa era inteso in quelli rimanenti 96,8584073465% di tutto l'utilizzo?
*a=*b;
qui solo il valore di b viene copiato in a. Spero che la proprietà sia di a che di b sia ancora con le stesse persone. Hai detto che la proprietà verrà trasferita. Come sarà?
auto_ptr
oggetto stesso. L'assegnazione al / dal suo valore indicato non ha alcun effetto sulla proprietà né rilevanza per la proprietà. Spero che tu non stia ancora usando auto_ptr
?
Ancora un altro modo di spiegare la differenza ...
Funzionalmente, il C ++ 11 std::unique_ptr
è il "fisso" std::auto_ptr
: entrambi sono adatti quando - in qualsiasi momento durante l'esecuzione - dovrebbe esserci un unico proprietario di puntatore intelligente per un oggetto puntato.
La differenza cruciale è nella costruzione della copia o nell'assegnazione da un altro puntatore intelligente senza scadenza, mostrato nelle =>
righe seguenti:
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
"ruba" silenziosamente la proprietà *ap
, lasciandolo ap
impostato su 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 std::auto_ptr
membro, fare una copia di un'istanza farà sì che release
il puntatore dell'istanza venga copiato: è una semantica strana e pericolosamente confusa poiché di solito copiare qualcosa non la modifica. È facile per l'autore della classe / struttura trascurare il rilascio del puntatore quando ragiona su invarianti e stato, e di conseguenza tenta accidentalmente di dereferenziare il puntatore intelligente mentre è null, o semplicemente non ha ancora previsto l'accesso / proprietà dei dati puntati.
auto_ptr non può essere utilizzato nei contenitori STL perché ha un costruttore di copie che non soddisfa i requisiti del contenitore CopyConstructible . unique_ptr non implementa un costruttore di copia, quindi i contenitori utilizzano metodi alternativi. unique_ptr può essere utilizzato nei contenitori ed è più veloce per gli algoritmi std 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