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

Copy Constructor to transfer ownership of a unique_ptr

本文关键字:ptr 所有权 unique 构造函数 转移 复制      更新时间:2023-10-16

我需要编写一个复制构造函数,它还可以转移被复制对象的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的复制构造函数?

我想你的意图或方法是错误的。

复制构造函数旨在创建参数的副本,但由于unique_ptr拥有唯一所有权,因此无法对其进行复制。实际上,可以使unique_ptr成员成为mutable,然后在复制构造函数中移动它指向的资源,但这绝对是疯狂的(std::auto_ptr就是这样做的,这也是它被弃用的原因)。

因此,您需要:

  • 向a和B添加一个move构造函数(+使复制构造函数被删除)
  • 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)) {
}

显然,由于std::unique_ptr的赋值运算符已被删除,因此不能只对其进行赋值。这是为了迫使程序员定义他想要的行为。

  1. 新项目拥有c_的所有权,使原始项目无效
  2. 新项目制作c_的副本,保留原始项目的有效性
  3. 新项目共享c_的所有权,以便新项目和原始项目都引用同一对象

情况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,因此c_的定义将变为:

std::shared_ptr<C> c_;

c_的构造将与您已经用于std::unique_ptr版本的c_的构造相同。因此,只需使用默认实现即可:

A foo;
A bar(foo);

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

从技术上讲,到

"编写一个复制构造函数,该构造函数还转移被复制对象的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,因为它真的很糟糕,除了破坏别人的代码之外,做这件事是没有意义的。

不是一个不复制的复制构造函数

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

  • 实现复制的普通复制构造函数,或

  • 将类设计更改为例如共享所有权