【问题标题】:Copy Constructor to transfer ownership of a unique_ptr复制构造函数以转移 unique_ptr 的所有权
【发布时间】:2015-05-21 09:17:07
【问题描述】:

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

【问题讨论】:

  • 那么当你复制的时候你想让原件失效?我建议删除复制构造函数并使类只能移动。
  • 如果原始对象是指原始对象 A,是的,它应该是“transferref”作为 B 类的成员。您能举个例子吗?
  • @Gabrielecswoosh 花一些时间阅读move-semantics 标签上的问题/答案。

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


【解决方案1】:

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

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

因此,您需要:

  • 向 A 和 B 添加移动构造函数(+ 删除复制构造函数)
  • unique_ptr 切换到 shared_ptr,但前提是 C 确实是要共享的

还有第三种选择,就是复制A的copy-constructor中unique_ptr指向的对象,即:

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

【讨论】:

  • 我不会认为意图是错误的。创建一个模拟常规类型的接口是非常好的,包装类型不能自然地暴露出来。
  • 我不同意你的看法。您可以复制包含 unique_ptr 的对象。例如,我可能会实现 LinkedList 类,该类将 unique_ptr 作为下一个元素的指针。这是否意味着我不能或不应该复制喜欢的列表?我可能想复制链表本身并将该副本保存在复制对象的 unique_ptr 中
  • @DavidHaim,但 OP 希望转移复制构造函数的所有权——这就是问题的标题。我认为这是错误的方法。
  • @DavidHaim 实际上 Adam Romanek 是对的,因为我的意图是转移所有权,而不是复制 unique_ptr 指向的对象。请问这个例子的移动构造函数的例子吗?
  • @Gabrielecswoosh,这里有:melpon.org/wandbox/permlink/bbvgsx31iuofzF4s。请注意,当您将只移动类型作为成员时,编译器默认为您生成相同的代码,例如unique_ptr: melpon.org/wandbox/permlink/7AlOoXZSOMOSLiFa(注意 A 中没有复制/移动构造函数,它仍然按预期工作)
【解决方案2】:

显然,您不能只对std::unique_ptrs 进行赋值,因为它们的赋值运算符已被删除。这是故意强迫程序员定义他想要的行为。

  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_ptrs 都被删除之前,不会删除此共享对象。

【讨论】:

    【解决方案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&amp; )

    我将那个类命名为Bad,因为它真的很糟糕,除了破坏别人的代码之外,这样做没有任何意义。

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2013-03-27
      • 2017-08-31
      • 2022-12-05
      • 2022-12-04
      • 2015-05-16
      • 2015-05-25
      • 2017-09-24
      • 1970-01-01
      • 2013-08-19
      相关资源
      最近更新 更多