让我们说我有一个类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复制构造函数的结果并执行正确的复制,但这是非常低效的
那么这个问题的最佳解决方案是什么?
答案 0 :(得分: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_ptr
,make_unique
,shared_ptr
,make_shared
和vector
共同完成了巨大的语言改进,这意味着您几乎不需要再次使用低级别且危险的new
或delete
个关键字。)