Perché è sbagliato usare std :: auto_ptr <> con contenitori standard?


217

Perché è sbagliato usare std::auto_ptr<>con contenitori standard?


5
Sicuramente un +1 su questo perché ho visto così tante persone sbagliare. È un'ottima domanda da porre.
twokats,

Si prega di leggere anche l'articolo correlato. Questa domanda è considerata qui dall'altra parte. Può essere utile per saperne di più sui contenitori auto_ptr e STL. stackoverflow.com/questions/8630552/…
nickolay


1
movesemantico e unique_ptrsono stati progettati per evitare i problemi relativi a auto_ptr. In C ++ 03, il linguaggio non era abbastanza potente per scrivere una classe del genere auto_ptrche si comportasse in modo corretto e sicuro in tutti gli scenari poiché il compilatore e il linguaggio non erano in grado di distinguere i valori re così alcuni "hack" sono stati usati per ottenere il comportamento desiderato La maggior parte delle volte.
Fil1970,

Bell'articolo: STL Containers e Auto_ptrs - Why They Don't Mix quantstart.com/articles/…
alfC

Risposte:


124

Lo standard C ++ afferma che un elemento STL deve essere "copia-costruibile" e "assegnabile". In altre parole, un elemento deve poter essere assegnato o copiato e i due elementi sono logicamente indipendenti. std::auto_ptrnon soddisfa questo requisito.

Prendi ad esempio questo codice:

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.

Per superare questo limite, è necessario utilizzare il std::unique_ptr, std::shared_ptro std::weak_ptrpuntatori intelligenti o gli equivalenti spinta se non si dispone di C ++ 11. Ecco la documentazione della libreria boost per questi suggerimenti intelligenti.


7
Dovresti anche considerare i contenitori puntatore boost, se non hai bisogno di proprietà condivisa.
Me22

4
unique_ptrnon consente inoltre la copia, pertanto alcune operazioni STL non funzioneranno correttamente a meno che non possano utilizzare la semantica di spostamento.
Mike Weller,

4
"Per superare questa limitazione, è necessario utilizzare std::unique_ptr": quel modello di classe può esistere solo a causa della semantica di spostamento (la sua specifica richiede riferimenti di valore), quindi fondamentalmente richiede C ++ 11. Tuttavia (e relativo) lo standard C ++ 11 non dice più che un tipo di elemento STL deve essere "copia-costruibile" e "assegnabile"; essere mossi costruibili e trasferibili è sufficiente. In effetti, le unique_ptristanze sono costruibili solo e assegnabili ai movimenti. Ma anche le auto_ptristanze! Di conseguenza, in C ++ 11 puoi fare auto_ptrciò che puoi fare unique_ptr.
Marc van Leeuwen,

@MarcvanLeeuwen a meno che tu resete releasequando necessario
maniaco del cricchetto,

2
@ratchetfreak: Hmm, non capisco. Che cosa? "a meno che tu resete release", non vedo come questo si applica a qualsiasi cosa nel mio commento. Si noti che entrambi auto_ptre unique_ptrhanno entrambi questi metodi, e lo fanno la stessa cosa in entrambi i casi.
Marc van Leeuwen,

66

La semantica della copia di auto_ptrnon è compatibile con i contenitori.

In particolare, la copia l'una auto_ptrdell'altra non crea due oggetti uguali poiché uno ha perso la proprietà del puntatore.

Più specificamente, la copia di auto_ptruna delle copie provoca il rilascio del puntatore. Quale di questi rimane nel contenitore non è definito. Pertanto, è possibile perdere casualmente l'accesso ai puntatori se si memorizza auto_ptrsnei contenitori.


39

Due articoli super eccellenti sull'argomento:


Perché penso che nel corso di quasi due anni, probabilmente ha affrontato il problema in questione.
Puppy,

27
@DeadMG: sì, hai ragione. Ma quello non era il mio scopo. Se qualcuno arriva a questo thread qualche volta e vuole saperne di più auto_ptre cose del genere, questi collegamenti saranno utili, ne sono sicuro.
Lazer,

Ci sono molti duplicati più recenti.
Cucciolo il

8
@DeadMG: questa domanda non è stata chiusa come duplicata ed è quindi aperta per l'estensione. Lazer ha detto ciò che non è stato detto prima qui. Immagino sia venuto per caso.
Sebastian Mach,

Le spiegazioni nel secondo link, che analizzano il problema dopo aver chiamato sort(), sono più chiare di tutte le risposte qui.
Chaosink

17

I contenitori STL devono essere in grado di copiare gli articoli in essi memorizzati e sono progettati per prevedere che l'originale e la copia siano equivalenti. gli oggetti puntatore automatico hanno un contratto completamente diverso, per cui la copia crea un trasferimento di proprietà. Ciò significa che i contenitori di auto_ptr presenteranno comportamenti strani, a seconda dell'uso.

C'è una descrizione dettagliata di ciò che può andare storto nell'articolo 8 di Effective STL (Scott Meyers) e anche una descrizione non così dettagliata nell'articolo 13 di Effective C ++ (Scott Meyers).


12

I contenitori STL memorizzano copie degli oggetti contenuti. Quando viene copiato un auto_ptr, il vecchio ptr viene impostato su null. Molti metodi di contenitore sono interrotti da questo comportamento.


Ma quando si utilizza unique_ptr si ottiene praticamente la stessa cosa dal momento che solo un unique_ptr può avere la proprietà dell'oggetto?
Tracer,

2
@Tracer unique_ptrcome qualsiasi oggetto C ++ 11 appropriato può trasferire la proprietà della sua risorsa solo quando è costruita o assegnata da mosse, assicurando che il programmatore debba deliberatamente passare un std::move(sourceObject)o un temporaneo, piuttosto che passare un lvalue e involontariamente / imprevedibilmente farlo mutare da l'incarico di copia ... che, come sottolineato in modo approfondito qui, era un problema centrale di auto_ptr.
underscore_d

4

La norma C ++ 03 (ISO-IEC 14882-2003) recita nella clausola 20.4.5 paragrafo 3:

[...] [ Nota: [...] auto_ptr non soddisfa i requisiti CopyConstructible e Assignable per gli elementi del contenitore della libreria standard e quindi un'istanza di un contenitore della libreria standard con un auto_ptr comporta un comportamento indefinito. - nota finale ]

La norma C ++ 11 (ISO-IEC 14882-2011) dice nell'appendice D.10.1 paragrafo 3:

[...] Nota: [...] le istanze di auto_ptr soddisfano i requisiti di MoveConstructible e MoveAssignable, ma non soddisfano i requisiti di CopyConstructible e CopyAssignable. - nota finale]

La norma C ++ 14 (ISO-IEC 14882-2014) dice nell'appendice C.4.2 Allegato D: caratteristiche di compatibilità:

Modifica : i modelli di classe auto_ptr, unary_function e binary_function, i modelli di funzione random_shuffle e i modelli di funzione (e i relativi tipi di ritorno) ptr_fun, mem_fun, mem_fun_ref, bind1st e bind2nd non sono definiti.
Motivazione : Sostituito da nuove funzionalità.
Effetto sulla funzione originale : il codice C ++ 2014 valido che utilizza questi modelli di classe e modelli di funzione potrebbe non essere compilato in questo standard internazionale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.