自动克隆unique_ptr

问题描述 投票:13回答:3

std::unique_ptr有一个删除的拷贝构造函数,这意味着如果你的类unique_ptr中有一个Foo作为数据成员,那么你必须为Foo编写自己的拷贝构造函数并手动深层复制该成员(即使编译器生成的拷贝构造函数会对所有其他成员都没问题)。

为了能够以多态方式进行复制,可以使用clone()方法模式。让我们假设我们的对象有一个像这样的克隆方法:

class Base {
    virtual std::unique_ptr<Base> clone() = 0;
};

Foo现在看起来像这样:

class Foo {
public:
    ...
    Foo(Foo const& other)
        : b(other.b->clone())
        , // init 10 more members that could otherwise be auto-copied just fine
          // with the automatically generated copy constructor
    {}
    ...

private:
    std::unique_ptr<Base> b;
    //10 more data members

};

现在,我找到了一种自动克隆Foo::b的方法,在unique_ptr上编写一个包装器,通过调用clone来定义复制构造函数和赋值。

template <typename T>
class auto_cloned_unique_ptr
{
private:
    std::unique_ptr<T> up;

public:
    // copy constructor
    auto_cloned_unique_ptr(auto_cloned_unique_ptr<T> const& other)
        : up(other.up->clone()) {}

    // copy assignment
    auto_cloned_unique_ptr<T>& operator =(auto_cloned_unique_ptr<T> const& other)
    {
        this->up = other.up->clone();
        return *this;
    }

    auto_cloned_unique_ptr(std::unique_ptr<T> _up)
        : up(std::move(_up)) {}

    // Delegate everything else to unique_ptr
    auto_cloned_unique_ptr(auto_cloned_unique_ptr<T>&& other)
        : up(std::move(other.up)) {}

    auto_cloned_unique_ptr<T>& operator =(auto_cloned_unique_ptr<T>&& other)
    {
        this->up = std::move(other.up);
        return *this;
    }

    auto operator *() const {return *up;}
    auto operator->() const {return up.operator->();}
    auto get() -> const {return up.get();}

};

现在,如果我们使用它,我们不需要定义自己的复制构造函数:

class Foo2 {
public:
    ...

private:
    auto_cloned_unique_ptr<Base> b;
    //10 more data members

};

这种方法是否非常不受欢迎(在unique_ptr上使用非标准包装)?

c++ c++11 clone copy-constructor unique-ptr
3个回答
1
投票

您的方法的问题是它正在改变unique_ptr的含义。 unique_ptr的关键在于它告诉谁是对象的所有者。如果为unique_ptr添加一个拷贝构造函数,那意味着什么?你在复制所有权吗? A和B都独一无二吗?那没有意义。如果他们共享所有权,那么您应该使用shared_ptr来指示共享所有权。如果您想拥有该对象副本的唯一所有者,您自然会通过make_unique(* pFoo)表示。使用基础对象和派生对象,使基础对象具有 virtual unique_ptr <Foo> Clone()const = 0; 是一个完全正常的结构。也就是说,派生类知道如何复制自己,因此它们不会生成切片副本,但是它们会向基类返回unique_ptr,以指示您将拥有它们生成的副本。在这些克隆操作中,是的,您将需要显式处理派生类的不可复制成员,因此您将无法仅使用默认或生成的复制构造函数。您需要回答“复制包含无法复制的内容的内容是什么意思?” 作为一个具体的例子,复制具有互斥锁的派生类意味着什么?如果它被锁定而另一个线程正在等待它怎么办?看看为什么很难给出一般答案?


0
投票

这种方法很好,但是你应该非常小心,不要在你不打算时克隆你的对象。

同样从unique_ptr继承可能会提高性能


0
投票

让我首先解释一下你想做什么:你想要Foo的每个实例在Base中都有自己的b实例;特别是,如果你复制一个Foo,副本将有自己的新Base,最初具有相同的“值”。换句话说,Base应该表现得像一个值。

同时,你不能将Base直接存储在Foo中,因为它是一个抽象类。换句话说,你想要bpolymorphic

你有它:你想要一个多态值。其他人已经认识到这种需求,并建议将C ++ 20用作polymorphic_value<Base>。从文档:

类模板polymorphic_value在自由存储分配的对象上赋予类似值的语义。 polymorphic_value可以保存从T公开派生的类的对象,并且复制polymorphic_value将复制派生类型的对象。

它有一个参考实现,您现在可以使用它。非常简单地说,它是围绕std::unique_ptr的包装,类似于你的建议。

© www.soinside.com 2019 - 2024. All rights reserved.