2011-11-29 30 views
6

Ho una classe con uno std::unique_ptr come membro della classe. Mi stavo chiedendo, come definire correttamente il costruttore di copie, dal momento che sto ricevendo il seguente messaggio di errore del compilatore: error C2248: std::unique_ptr<_Ty>::unique_ptr : cannot access private member declared in class 'std::unique_ptr<_Ty>. Il mio progetto di classe sembra qualcosa di simile:Copia costruttore con puntatore intelligente

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); 
} 

risposta

5

Supponendo che l'obiettivo è quello di copiare-costruire la barra unica di proprietà,

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, grazie. Ho ora un altro problema. La classe 'Bar' è in realtà una classe base astratta, e quindi sto ricevendo un nuovo messaggio di errore:' errore C2259: 'Bar': impossibile istanziare la classe astratta', C'è una soluzione, oltre a trasformare la classe base astratta, in una semplice classe base? – Tin

+2

@Tin: in tal caso, sarà necessario aggiungere una funzione 'clone()' virtuale alla classe base, sovrascritta in ogni classe derivata per creare una copia usando 'new'. Quindi l'inizializzatore diventa 'bar (foo.bar? Foo.bar-> clone(): nullptr)'. –

+0

@Tin Le domande frequenti su C++ chiamano ["virtual constructor"] (http://www.parashift.com/c++-faq-lite/virtual-functions.html#faq-20.8) – Cubbi

2

Unique_ptr documentazione:

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. 

non puoi copiarlo perché due oggetti non possono possederlo.

Provare a passare a std :: shared_ptr.

EDIT Devo sottolineare che ciò farebbe sì che entrambi gli oggetti abbiano un puntatore allo stesso oggetto. Se vuoi copiare l'oggetto di proprietà esclusiva, la soluzione di Cubbi è quella corretta.

+0

@ w00te, grazie. Un'altra domanda. Cosa succede se la classe Bar è in realtà una classe base astratta? Ricevo un nuovo messaggio di errore: 'errore C2259: 'Barra': impossibile istanziare la classe astratta'.C'è qualche soluzione, oltre a trasformare la classe base astratta, in una semplice classe base? – Tin

+0

La soluzione Cubbi crea un nuovo oggetto Bar da contenere all'interno di unique_ptr nella nuova classe. Se la barra è astratta allora non può funzionare - dovrebbe invece creare un nuovo oggetto della classe derivata applicabile. Dovrai aggiungere la logica per raggiungere questo obiettivo. –

2

Una possibilità è creare un nuovo tipo clone_ptr per questo.

Di seguito è riportato un esempio rudimentale di clone_ptr che richiama il costruttore di copia (e il distruttore) corretto di un oggetto derivato. Questo viene fatto creando un helper "cancellazione tipo" quando viene creato lo clone_ptr.

Altre implementazioni possono essere trovate su 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); 
    } 
}; 

Vedi esempio di utilizzo: http://ideone.com/LnWa3

(Ma forse non si ha realmente bisogno di copia gli oggetti, e potrebbe invece esplorare le possibilità della semantica muoversi per esempio, si può avere un vector<unique_ptr<T>>. , purché non utilizzi funzioni che copiano i contenuti.)

Problemi correlati