2011-09-09 10 views
6

Ho appreso che STL può vietare al programmatore di inserire un auto_ptr in un contenitore. Per esempio seguente codice non sarebbe compilare:Perché vector.push_back (auto_ptr) non verrebbe compilato?

auto_ptr<int> a(new int(10)); 
    vector<auto_ptr<int> > v; 
    v.push_back(a); 

auto_ptr ha il costruttore di copia, perché questo codice può anche compilare?

+1

So che non dovrei usare l'auto_ptr in stl a causa della copia semantica. Ma la mia domanda è ** come viene implementata la stl in modo che possa impedirti di farlo? ** Nel mio codice di esempio, non può nemmeno compilare. – frinker

+1

Puoi pubblicare l'errore di compilazione? –

+0

@xanatos: nessun costruttore di copia è 'const'! –

risposta

11

Guardando the definition of std::auto_ptr:

namespace std { 

    template <class Y> struct auto_ptr_ref {}; 


    template <class X> 
    class auto_ptr { 
    public: 
     typedef X element_type; 

     // 20.4.5.1 construct/copy/destroy: 
     explicit   auto_ptr(X* p =0) throw(); 
          auto_ptr(auto_ptr&) throw(); 
     template <class Y> auto_ptr(auto_ptr<Y>&) throw(); 

     auto_ptr&      operator=(auto_ptr&) throw(); 
     template <class Y> auto_ptr& operator=(auto_ptr<Y>&) throw(); 
     auto_ptr&      operator=(auto_ptr_ref<X>) throw(); 

     ~auto_ptr() throw(); 

     // 20.4.5.2 members: 
     X&  operator*() const throw(); 
     X*  operator->() const throw(); 
     X*  get() const throw(); 
     X*  release() throw(); 
     void reset(X* p =0) throw(); 

     // 20.4.5.3 conversions: 
            auto_ptr(auto_ptr_ref<X>) throw(); 
     template <class Y> operator auto_ptr_ref<Y>() throw(); 
     template <class Y> operator auto_ptr<Y>() throw(); 
    }; 

} 

Sebbene esista un costruttore di copie, prende un riferimento a non- const. I temporanei non possono vincolare a questo, quindi al tipo viene effettivamente proibito di lavorare all'interno dei contenitori in qualsiasi luogo in cui vengono utilizzati i temporanei; inoltre, push_back accetta un riferimento a const, quindi a causa della correzione const, è impossibile che il nuovo elemento interno venga copiato dall'argomento di push_back.

(Quella pagina di Wikipedia dice che "a causa della sua semantica della copia, auto_ptr non può essere utilizzato nei contenitori STL che possono eseguire copie di elementi nelle loro operazioni"; ciò non significa che i contenitori esaminino magicamente il codice all'interno del costruttore di copie decidere se vuole fare il lavoro di tipo come un tipo di elemento. Invece, è solo circa la firma della funzione.)

in ogni caso, std::auto_ptr è deprecato a partire dal C++ 11, perché, secondo il parere di alcuni, std::auto_ptr è sciocco. Spiacente, std::auto_ptr.

+0

+1, anche qui discusso: http://stackoverflow.com/q/3316514 – sharptooth

+1

Non sono assolutamente d'accordo, std :: auto_ptr è perfetto per risolvere una serie di problemi. Purtroppo gli sviluppatori lo usano impropriamente. –

+0

+1, vedo, grazie amico! – frinker

0

Perché std :: auto_ptr non è compatibile con il contenitore stl.

std :: auto_ptr sta usando copia singola proprietà semantica, il contenitore STL ha bisogno di copiare costruire un oggetto (e alcuni algoritmi bisogno di assegnarlo)

Si dovrebbe utilizzare un riferimento contato puntatore intelligente (boost :: shared_ptr)

EDIT

Ad esempio, questa è la firma del push_back

void push_back (const T& x); 

Il problema è che std :: auto_ptr è speciale e il costruttore di copie e assegnare la firma dell'operatore sono diversi. NON sono costanti. Si modifica un auto_ptr se lo si copia.

auto_ptr& operator= (auto_ptr& a) throw(); 

auto_ptr (auto_ptr& a) throw(); 

Non è possibile fornire un auto_ptr che soddisfi i requisiti di push_back.

+0

Oppure un discreto puntatore a proprietà singola con semantica di spostamento, come 'std :: unique_ptr'. –

+0

dai un'occhiata agli articoli 13-17 di Effective C++, non è specifico con auto_ptr, ma è molto utile per capire il tuo problema. –

+3

So che non dovrei usare l'auto_ptr in stl a causa della copia semantica. Ma la mia domanda è ** come viene implementata la stl in modo che possa impedirti di farlo? ** Nel mio codice di esempio, non può nemmeno compilare. – frinker

0

Le altre risposte sono bang su about auto_ptr.

di fare ciò che si sta cercando di fare uso std :: unique_ptr se a vostra disposizione (C++ 11), se non è possibile utilizzare uno shared_ptr

6

Sul particolare problema di come il compilatore rileva tale situazione (o come fa l'STL a causare un errore), dovresti leggere l'output esatto del compilatore, conterrà un sacco di errori che porteranno al fallimento eseguire una conversione da const X a X in quanto elimina il qualificatore const, dove X può essere std::auto_ptr<> direttamente oppure un tipo di dettaglio interno.

In particolare, std::vector::push_back prende l'argomento const &, ed internamente cercheranno di copiare costruire un elemento all'interno della matrice dinamica utilizzando il costruttore copia disponibile, che nel caso di std::auto_ptr richiede un riferimento non-const. Qualcosa sulle linee di:

void push_back(std::auto_ptr<int> const & x) { 
    // ensure enough capacity if needed... 
    new (buffer + size()) std::auto_ptr<int>(x); // !!! cannot bind x to non-const& 
    // complete the operation (adjust end pointer, and such) 
}