带有智能指针的std::vector的深度复制构造函数



假设我有一个类FooContainer,它聚合了类型为Foo的unique_ptr对象

#include <vector>
#include <memory>
class FooContainer
{
protected:
std::vector<std::unique_ptr<Foo>> many;
//other attributes
public:
FooCoontainer(const FooContainer&);
//handling functions for Foo
};

问题是如何正确实现深层复制构造函数,以及它的语法是什么。简单地指定

FooContainer::FooContainer(const FooContainer& fc)
{
many=fc.many;
}

将尝试复制指针,并且(幸运的是)编译器不允许使用unique_ptr。所以我需要这样写

FooContainer::FooContainer(const FooContainer& fc)
{
many.reserve(fc.many.size());
for(int i=0;i<fc.many.size();i++)
many.emplace_back(new Foo(*fc.many[i]));//assume that Foo has a copy constructor
}

是这样做的吗?或者我应该使用shared_ptr而不是unique_ptr?

我还有一个问题。
使用智能指针(以及上面代码中的protected)的原因是,我有一个派生类BarContainer,它聚集了许多对象Bar,而这些对象又是Foo的子类。由于Bar的处理与Foo非常相似,因此与两个独立的类相比,这种方法可以节省大量重复的代码。

然而,

。BarContainer的复制构造函数有问题。它会调用FooContainer的复制构造函数,它会继续只复制Foo部分而不是整个Bar。更糟糕的是,对Bar的虚方法的任何调用都会调用Foo的版本。所以我需要一种方法来重写这种行为。不能将复制构造函数设置为虚函数。Bar的复制构造函数也可以丢弃Foo复制构造函数的结果并执行正确的复制,但这是相当低效的

那么这个问题的最佳解决方案是什么呢?

或者我应该使用shared_ptr而不是unique_ptr?

这取决于你是需要深层复制还是浅层复制(这意味着对其中一个的更改也会在另一个中可见)。

然而,

。BarContainer的复制构造函数有问题。它将调用FooContainer的复制构造函数,它将向前移动,只复制Foo部分,而不是整个Bar。

通常的解决方法是给你的基类一个虚方法clone:
class Foo {
public:
    Foo(Foo&&) = default;
    Foo& operator=(Foo&&) = default;
    virtual ~Foo() = 0;
    virtual std::unique_ptr<Foo> clone() const = 0;
protected: // or public if appropriate
    Foo(const Foo&);
    Foo& operator=(const Foo&);
};
class Bar : public Foo {
public:
    virtual std::unique_ptr<Foo> clone() const;
};
std::unique_ptr<Foo> Bar::clone() const {
    return make_unique<Bar>(*this);
}

如果Foo不是抽象的,它也会有clone()的实际实现。

FooContainer::FooContainer(const FooContainer& fc)
{
    many.reserve(fc.many.size());
    for (auto const& fptr : fc.many)
        many.emplace_back(fptr->clone());
}

我使用了一个模板函数make_unique,它在c++ 11标准中被意外地遗忘了,但很快就会正式发布。如果你的编译器没有这样的文件,你可以把自己的文件放到头文件中:

template <typename T, typename... Args>
std::unique_ptr<T> make_unique(Args&& ... args) {
    return std::unique_ptr<T>( new T(std::forward<Args>(args)...) );
}

(unique_ptr, make_unique, shared_ptr, make_sharedvector一起完成了巨大的语言改进,这意味着您几乎再也不需要低级和危险的newdelete关键字了。)

相关内容

  • 没有找到相关文章

最新更新