2011-11-29 10 views
6

Tengo una clase con un std::unique_ptr como miembro de la clase. Me preguntaba cómo definir correctamente el constructor de copia, ya que recibo el siguiente mensaje de error del compilador: error C2248: std::unique_ptr<_Ty>::unique_ptr : cannot access private member declared in class 'std::unique_ptr<_Ty>. Mi diseño de la clase se ve algo como:Copiar el constructor con el puntero inteligente

template <typename T> 
class Foo{ 
    public: 
     Foo(){}; 
     Foo(Bar<T> *, int); 
     Foo(const Foo<T> &); 
     ~Foo(){}; 

     void swap(Foo<T> &); 
     Foo<T> operator = (Foo<T>); 

    private: 
     std::unique_ptr<Bar> m_ptrBar; 
     int m_Param1; 

}; 

template < typename T > 
Foo<T>::Foo(const Foo<T> & refFoo) 
:m_ptrBar(refFoo.m_ptrBar), 
m_Param1(refFoo.m_Param1) 
{ 
    // error here! 
} 

template < typename T > 
void Foo<T>::swap(Foo<T> & refFoo){ 
    using std::swap; 
    swap(m_ptrBar, refFoo.m_ptrBar); 
    swap(m_Param1, refFoo.m_Param1); 
} 

template < typename T > 
Foo<T> Foo<T>::operator = (Foo<T> Elem){ 
    Elem.swap(*this); 
    return (*this); 
} 

Respuesta

5

Suponiendo que el objetivo es copiar-construir la barra de propiedad exclusiva y,

documentación
template < typename T > 
Foo<T>::Foo(const Foo<T> & refFoo) 
: m_ptrBar(refFoo.m_ptrBar ? new Bar(*refFoo.m_ptrBar) : nullptr), 
    m_Param1(refFoo.m_Param1) 
{ 
} 
+0

@ Cubbi, gracias. Ahora tengo otro problema. La clase 'Bar' es en realidad una clase base abstracta, y por lo tanto recibo un nuevo mensaje de error:' error C2259: 'Bar': no ​​se puede crear una instancia de clase abstracta', ¿Hay alguna solución, además de convertir la clase base abstracta, en una clase base simple? – Tin

+2

@Tin: en ese caso, deberá agregar una función virtual 'clone()' pura a la clase base, anulada en cada clase derivada para crear una copia usando 'new'. Entonces el inicializador se convierte en 'bar (foo.bar? Foo.bar-> clone(): nullptr)'. –

+0

@Tin Las preguntas frecuentes de C++ llaman a eso ["constructor virtual"] (http://www.parashift.com/c++faq-lite/virtual-functions.html#faq-20.8) – Cubbi

2

unique_ptr:

Stores a pointer to an owned object. The object is owned by no other unique_ptr. 
The object is destroyed when the unique_ptr is destroyed. 

Usted no puede copiar porque dos objetos no pueden poseerlo.

Intenta cambiar a std :: shared_ptr.

EDIT Debo señalar que esto haría que ambos objetos tengan un puntero al mismo objeto. Si desea copiar el objeto de propiedad única, la solución de Cubbi es la correcta.

+0

@ w00te, gracias. Una pregunta más. ¿Qué pasa si la clase Bar es en realidad una clase base abstracta? Recibo un nuevo mensaje de error: 'error C2259: 'Barra': no ​​se puede crear una instancia de clase abstracta'.¿Hay alguna solución, además de convertir la clase base abstracta, en una clase base simple? – Tin

+0

La solución de Cubbi crea un nuevo objeto Bar que se incluirá en el unique_ptr en la nueva clase. Si la barra es abstracta, entonces eso no puede funcionar; en su lugar, tendría que crear un nuevo objeto de la clase derivada aplicable. Tendrás que agregar lógica para lograr eso. –

2

Una posibilidad es crear un nuevo tipo clone_ptr para esto.

A continuación se muestra un ejemplo rudimentario de clone_ptr que invoca el constructor de copia correcto (y el destructor) de un objeto derivado. Esto se hace aquí al crear un auxiliar "borrado de tipo" cuando se crea el clone_ptr.

Otras implementaciones se pueden encontrar en Internet.

#include <memory> 

namespace clone_ptr_detail 
{ 
template <class T> 
class clone_ptr_helper_base 
{ 
public: 
    virtual ~clone_ptr_helper_base() {} 
    virtual T* clone(const T* source) const = 0; 
    virtual void destroy(const T* p) const = 0; 
}; 

template <class T, class U> 
class clone_ptr_helper: public clone_ptr_helper_base<T> 
{ 
public: 
    virtual T* clone(const T* source) const 
    { 
     return new U(static_cast<const U&>(*source)); 
    } 
    virtual void destroy(const T* p) const 
    { 
     delete static_cast<const U*>(p); 
    } 
}; 
} 

template <class T> 
class clone_ptr 
{ 
    T* ptr; 
    std::shared_ptr<clone_ptr_detail::clone_ptr_helper_base<T>> ptr_helper; 
public: 
    template <class U> 
    explicit clone_ptr(U* p): ptr(p), ptr_helper(new clone_ptr_detail::clone_ptr_helper<T, U>()) {} 

    clone_ptr(const clone_ptr& other): ptr(other.ptr_helper->clone(other.ptr)), ptr_helper(other.ptr_helper) {} 

    clone_ptr& operator=(clone_ptr rhv) 
    { 
     swap(rhv); 
     return *this; 
    } 
    ~clone_ptr() 
    { 
     ptr_helper->destroy(ptr); 
    } 

    T* get() const { /*error checking here*/ return ptr; } 
    T& operator*() const { return *get(); } 
    T* operator->() const { return get(); } 

    void swap(clone_ptr& other) 
    { 
     std::swap(ptr, other.ptr); 
     ptr_helper.swap(other.ptr_helper); 
    } 
}; 

Ver ejemplo de uso: http://ideone.com/LnWa3

(Pero tal vez usted no necesita realmente copia sus objetos, y más bien podrían explorar las posibilidades de la semántica movimiento Por ejemplo, puede tener un vector<unique_ptr<T>>. , siempre que no utilice funciones que copien el contenido.)

Cuestiones relacionadas