2011-09-09 8 views
6

Me enteré de que STL puede prohibir al programador colocar un auto_ptr en un contenedor. Por ejemplo siguiente código no se compilará:¿Por qué vector.push_back (auto_ptr) no compila?

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

auto_ptr tiene el constructor de copia, ¿por qué este código incluso puede compilar?

+1

Sé que no debería usar el auto_ptr en stl debido a la semántica de copia. Pero mi pregunta es ** ¿cómo se implementa el stl para que pueda prohibirte hacerlo? ** En mi código de muestra, ni siquiera puede compilar. – frinker

+1

¿Puedes publicar el error de compilación? –

+0

@xanatos: ¡Ningún constructor de copia es 'const'! –

Respuesta

11

En cuanto a 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(); 
    }; 

} 

Aunque hay un constructor de copia, toma como referencia no const. Es posible que los temporarios no se vinculen a esto, por lo que se prohíbe efectivamente que el tipo funcione dentro de los contenedores en cualquier lugar donde se usen los temporales; Además, push_back acepta una referencia a const, por lo que debido a const -corrección es imposible para el nuevo elemento interno copiar-construido del argumento push_back.

(Esa página de Wikipedia dice que "debido a su semántica de copia, auto_ptr no puede usarse en contenedores STL que pueden realizar copias de elementos en sus operaciones", esto no significa que los contenedores examinen mágicamente el código dentro del constructor de copias para decidir si quiere hacer el trabajo de tipo como un tipo de elemento. en su lugar, se trata sólo de la firma de la función.)

de todos modos, std::auto_ptr está obsoleta de C++ 11, ya que, en opinión de algunos, std::auto_ptr es tonto. Lo siento, std::auto_ptr.

+0

+1, también discutido aquí: http://stackoverflow.com/q/3316514 – sharptooth

+1

Estoy totalmente en desacuerdo, std :: auto_ptr es perfecto para resolver una serie de problemas. Lamentablemente, los desarrolladores lo usan mal. –

+0

+1, ya veo, gracias hombre! – frinker

0

Porque std :: auto_ptr no es compatible con stl container.

std :: auto_ptr está utilizando la propiedad única copia semántica, el contenedor STL tiene que copiar la construcción de un objeto (y algunos algoritmos necesitan para asignarlo)

Se debe utilizar una referencia contado puntero inteligente (boost :: shared_ptr)

EDITAR

Por ejemplo, esta es la firma de push_back

void push_back (const T& x); 

El problema es que std :: auto_ptr es especial y el constructor de copia y la firma del operador de asignación son diferentes. NO son const. Modifica un auto_ptr si lo copia.

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

auto_ptr (auto_ptr& a) throw(); 

No puede proporcionar un auto_ptr que cumpla con el requisito de push_back.

+0

O un puntero de propiedad único decente con semántica de movimiento, como 'std :: unique_ptr'. –

+0

eche un vistazo a los elementos 13-17 de C++ efectivo, no es específico con auto_ptr, pero es muy útil para comprender su problema. –

+3

Sé que no debería usar el auto_ptr en stl debido a la semántica de copia. Pero mi pregunta es ** ¿cómo se implementa el stl para que pueda prohibirte hacerlo? ** En mi código de muestra, ni siquiera puede compilar. – frinker

0

Las otras respuestas son interesantes sobre auto_ptr.

para hacer lo que está tratando de hacer uso std :: unique_ptr si a su disposición a usted (C++ 11) si no se puede utilizar un shared_ptr

6

Sobre el problema particular de cómo el compilador detecta esa situación (o cómo el STL causa un error allí), debe leer la salida exacta del compilador, que contendrá un montón de errores que conducirán a la falla para realizar una conversión de const X a X ya que descarta el calificador const, donde X puede ser std::auto_ptr<> directamente o bien un tipo de detalle interno.

En particular, std::vector::push_back toma el argumento de const &, e internamente se tratará de copiar la construcción de un elemento dentro de la matriz dinámica usando el constructor de copia disponible, que en el caso de std::auto_ptr requiere una referencia no const. Algo en las líneas de:

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) 
} 
Cuestiones relacionadas