Скопируйте конструктор с умным указателем - PullRequest
6 голосов
/ 29 ноября 2011

У меня есть класс с одним std::unique_ptr в качестве члена класса. Мне было интересно, как правильно определить конструктор копирования, так как я получаю следующее сообщение об ошибке компилятора: error C2248: std::unique_ptr<_Ty>::unique_ptr : cannot access private member declared in class 'std::unique_ptr<_Ty>. Мой класс дизайна выглядит примерно так:

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

Ответы [ 3 ]

5 голосов
/ 29 ноября 2011

Предполагая, что цель состоит в том, чтобы создать копию уникального бара,

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)
{
}
2 голосов
/ 30 ноября 2011

Для этого можно создать новый тип clone_ptr.

Ниже приведен элементарный пример clone_ptr, который вызывает правильный конструктор копирования (и деструктор) производного объекта.Это делается здесь путем создания помощника «стирания типа» при создании clone_ptr.

Другие реализации можно найти в Интернете.

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

См. Пример использования: http://ideone.com/LnWa3

(Но, возможно, вам на самом деле не нужно копировать ваших объектов, и вы могли бы скорее изучить возможности перемещениясемантика. Например, вы можете иметь vector<unique_ptr<T>>, если вы не используете функции, которые копируют содержимое.)

2 голосов
/ 29 ноября 2011

Документация 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.

Вы не можете скопировать это, потому что два объекта не могут владеть им.1008 * РЕДАКТИРОВАТЬ Я должен указать, что это заставит оба объекта иметь указатель на тот же объект.Если вы хотите скопировать объект с уникальной собственностью, решение Cubbi будет правильным.

...