提问者:小点点

具有unique_ptr的类的复制构造函数


如何为具有成员变量的类实现复制构造函数?我只考虑C++11。


共3个答案

匿名用户

由于不能共享,您需要深度复制其内容或将转换为

class A
{
   std::unique_ptr< int > up_;

public:
   A( int i ) : up_( new int( i ) ) {}
   A( const A& a ) : up_( new int( *a.up_ ) ) {}
};

int main()
{
   A a( 42 );
   A b = a;
}

正如NPE提到的,您可以使用move-ctor而不是copy-ctor,但这会导致类的语义不同。move-ctor需要通过:

A( A&& a ) : up_( std::move( a.up_ ) ) {}

拥有一套完整的必要运算符还会导致

A& operator=( const A& a )
{
   up_.reset( new int( *a.up_ ) );
   return *this,
}

A& operator=( A&& a )
{
   up_ = std::move( a.up_ );
   return *this,
}

如果您想在中使用您的类,您基本上必须决定向量是否是对象的唯一所有者,在这种情况下,使类可移动而不可复制就足够了。如果省略了copy-ctor和copy-assignment,编译器将指导您如何将std::vector与仅移动类型一起使用。

匿名用户

在类中具有的通常情况是能够使用继承(否则普通对象通常也会这样做,请参见RAII)。对于这个案例,这个线程到现在都没有合适的答案。

那么,起点就在这里:

struct Base
{
    //some stuff
};

struct Derived : public Base
{
    //some stuff
};

struct Foo
{
    std::unique_ptr<Base> ptr;  //points to Derived or some other derived class
};

。。。目标是,正如所说的,使可复制。

为此,需要对包含的指针进行深度复制,以确保正确复制派生类。

这可以通过添加以下代码来实现:

struct Base
{
    //some stuff

    auto clone() const { return std::unique_ptr<Base>(clone_impl()); }
protected:
    virtual Base* clone_impl() const = 0;
};

struct Derived : public Base
{
    //some stuff

protected:
    virtual Derived* clone_impl() const override { return new Derived(*this); };                                                 
};

struct Foo
{
    std::unique_ptr<Base> ptr;  //points to Derived or some other derived class

    //rule of five
    ~Foo() = default;
    Foo(Foo const& other) : ptr(other.ptr->clone()) {}
    Foo(Foo && other) = default;
    Foo& operator=(Foo const& other) { ptr = other.ptr->clone(); return *this; }
    Foo& operator=(Foo && other) = default;
};

这里基本上有两件事在进行:

> 的复制构造函数被删除,这些构造函数在中被隐式删除。移动构造函数可以简单地由添加…这只是为了让编译器知道通常的移动构造函数不会被删除(这是可行的,因为已经有一个移动构造函数可以在这种情况下使用)。

对于的复制构造函数,没有类似的机制,因为没有的复制构造函数。因此,必须构造一个新的,用原始指针的副本填充它,并将它用作复制类的成员。

在涉及继承的情况下,必须认真做好原被指人的复印工作。原因是在上面的代码中通过执行简单的复制会导致切片,即只复制对象的基本组件,而缺少派生部分。

为了避免这种情况,必须通过clone-pattern进行复制。其思想是通过一个虚函数进行复制,该函数在基类中返回一个。但是,在派生类中,它通过协方差进行扩展,返回,这个指针指向新创建的派生类副本。然后基类可以通过基类指针访问这个新对象,将其包装到中,并通过从外部调用的实际函数返回它。

匿名用户

尝试此帮助程序创建深度副本,并在源unique_ptr为空时进行处理。

    template< class T >
    std::unique_ptr<T> copy_unique(const std::unique_ptr<T>& source)
    {
        return source ? std::make_unique<T>(*source) : nullptr;
    }

例如:

class My
{
    My( const My& rhs )
        : member( copy_unique(rhs.member) )
    {
    }

    // ... other methods

private:
    std::unique_ptr<SomeType> member;
};