复制构造函数以转移unique_ptr的所有权

时间:2015-03-18 14:20:56

标签: c++ copy-constructor unique-ptr ownership

我需要编写一个复制构造函数,它还传递被复制对象的unique_ptr成员的所有权。情况如下:

class C{
   // C class stuff       
};

class A{
public:
    public A();
    public A(const A& a);
private:
    std::unique_ptr<C> c_;
}

class B{

public:

    B(const A& b) : a_(a){}

private:
     A a_;


};

我应该如何为A实现复制构造函数?

3 个答案:

答案 0 :(得分:6)

我猜你的意图或做法是错误的。

复制构造函数用于创建参数的副本,但由于unique_ptr维护唯一所有权,因此无法复制它。您可以实际上创建unique_ptr成员mutable,然后将其指向的资源移动到复制构造函数中,但这绝对是疯狂的(这是std::auto_ptr所做的事情。这就是它被弃用的原因。

因此,您需要:

  • 将一个move-constructor添加到A和B(+ make copy-constructor deleted)
  • unique_ptr切换到shared_ptr,但前提是C实际上是要共享

还有第三种选择,即在A的复制构造函数中复制由unique_ptr指向的对象,即:

A::A(const A& a) : c_(std::unique_ptr<C>(a.c_ ? new C(*a.c_) : nullptr)) {
}

答案 1 :(得分:4)

显然,您不能只删除std::unique_ptr s,因为它们的赋值运算符已被删除。这是为了迫使程序员定义他想要的行为。

  1. 新项目取得c_的所有权,使原始项目无效。
  2. 新项目会复制c_,保留原始项目的有效性。
  3. 新项目共享c_的所有权,以便新项目和原始项目都引用同一个对象。

  4. 案例1 中,您正在寻找的是移动构造函数,默认移动构造函数将正常工作。所以你不需要编写任何代码,你可以这样做:

    A temp;
    A foo(std::move(temp));
    

    请注意temp移动后无效。

    案例2 中,您需要向A添加自定义复制构造函数,以创建原始c_的副本:

    A(const A& a):c_(new C(*(a.c_))){}
    

    A中定义后,您可以执行以下操作:

    A foo(A());
    

    请注意,这取决于C的复制构造函数是否正常运行。

    案例3 中,您需要从使用A到使用std::unique_ptr从根本上改变std::shared_ptr,因此{{1}的定义1}}将成为:

    c_

    std::shared_ptr<C> c_; 的构建方式与c_ std::unique_ptrc_的用法相同。所以只需使用您可以执行的默认实现:

    A foo;
    A bar(foo);
    

    现在foobar指向同一个C对象,并分享对象的所有权。在所有引用它的shared_ptr被删除之前,不会删除此共享对象。

答案 2 :(得分:3)

技术上,

  

编写一个复制构造函数,该构造函数还传输正在复制的对象的unique_ptr成员的所有权

你可以这样做:

class Bad
{
private:
    unique_ptr<int> p_;
public:
    Bad(): p_( new int(666) ) {}
    Bad( Bad& other )
       : p_( move( other.p_ ) )
    {}
};

因为除了更传统的Bad( const Bad& )之外,复制构造函数还可以包含此签名以及另外两个签名。

我将该类命名为Bad,因为它非常糟糕,除了破坏其他人的代码之外,做这件事是没有意义的。

而不是不复制的复制构造函数,

  • 实现移动的移动构造函数,或

  • 实现复制

  • 的普通复制构造函数
  • 将班级设计改为例如共享所有权