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.