首页 文章

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

提问于
浏览
3

假设我有一个类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?

我还有一个问题 .
寻找智能指针(以及上面代码中的受保护的)的原因是我派生了类BarContainer,它聚合了许多对象Bar,它们又是Foo的子类 . 由于Bar的处理与Foo非常相似,因此与两个单独的类相比,这种方法可以节省大量重复代码 .

然而, . BarContainer的复制构造函数存在问题 . 它将是FooContainer的调用复制构造函数,它将使用agead并仅复制Foo部分而不是整个Bar . 更糟糕的是,任何Bar的虚方法调用都会调用Foo的版本 . 所以我需要一种方法来覆盖这种行为 . 使复制构造函数虚拟是不可能的 . Bar的复制构造函数也可以丢弃Foo复制构造函数的结果并执行正确的复制,但这样效率很低

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

1 回答

  • 2

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

    这取决于您是需要深拷贝还是可以使用浅拷贝(意味着对另一个的更改也会在另一个中可见) .

    但是, BarContainer的复制构造函数存在问题 . 它将是FooContainer的调用复制构造函数,它将使用agead并仅复制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_ptrmake_uniqueshared_ptrmake_sharedvector 完成了巨大的语言改进意味着你几乎不再需要低级别和危险的 newdelete 关键字 . )

相关问题