tma*_*ric 7 c++ smart-pointers copy-constructor assignment-operator
从boost库文档中我读到了这个:
从概念上讲,智能指针被视为拥有指向的对象,因此在不再需要时负责删除对象.
我有一个非常简单的问题:我想使用RAII作为可复制和可分配类的指针属性.
复制和赋值操作应该很深:每个对象都应该有自己的实际数据副本.此外,RTTI需要可用于属性(它们的类型也可以在运行时确定).
我应该搜索可复制智能指针的实现(数据很小,所以我不需要复制写入指针),或者我是否将复制操作委托给我的对象的复制构造函数,如本答案所示?
我可以选择哪种智能指针用于可复制和可分配的类的简单RAII?(我认为带有委托复制/赋值操作的unique_ptr到类复制构造函数和赋值运算符会做出正确的选择,但我不确定)
这是使用原始指针的问题的伪代码,它只是一个问题描述,而不是正在运行的C++代码:
// Operation interface
class ModelOperation
{
public:
virtual void operate = ();
};
// Implementation of an operation called Special
class SpecialModelOperation
:
public ModelOperation
{
private:
// Private attributes are present here in a real implementation.
public:
// Implement operation
void operate () {};
};
// All operations conform to ModelOperation interface
// These are possible operation names:
// class MoreSpecialOperation;
// class DifferentOperation;
// Concrete model with different operations
class MyModel
{
private:
ModelOperation* firstOperation_;
ModelOperation* secondOperation_;
public:
MyModel()
:
firstOperation_(0),
secondOperation_(0)
{
// Forgetting about run-time type definition from input files here.
firstOperation_ = new MoreSpecialOperation();
secondOperation_ = new DifferentOperation();
}
void operate()
{
firstOperation_->operate();
secondOperation_->operate();
}
~MyModel()
{
delete firstOperation_;
firstOperation_ = 0;
delete secondOperation_;
secondOperation_ = 0;
}
};
int main()
{
MyModel modelOne;
// Some internal scope
{
// I want modelTwo to have its own set of copied, not referenced
// operations, and at the same time I need RAII to for the operations,
// deleting them automatically as soon as it goes out of scope.
// This saves me from writing destructors for different concrete models.
MyModel modelTwo (modelOne);
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
如果您接受对类型的某些要求,则可以在不需要为所有类型实现虚拟克隆功能的情况下完成此操作.特殊要求是类型具有可访问的拷贝构造器,由于可能的意外切片,一些人认为这些构造器是不合需要的.但是,正确使用友情可以减轻这种缺点.
如果这是可以接受的,可以通过在提供复制功能的接口下擦除派生类型来解决此问题:
template <typename Base>
struct clonable {
// virtual copy
// this clone function will be generated via templates
// no boilerplate is involved
virtual std::unique_ptr<clonable<Base>> clone() const = 0;
// expose the actual data
virtual Base* get() = 0;
virtual Base const* get() const = 0;
// virtual destructor
// note that this also obviates the need for a virtual destructor on Base
// I would probably still make it virtual, though, just in case
virtual ~clonable() = default;
};
Run Code Online (Sandbox Code Playgroud)
此接口由最衍生类型模板化的类实现,因此知道如何通过复制构造函数生成正常副本.
template <typename Base, typename Derived>
struct clonable_holder : clonable<Base> {
// I suppose other constructors could be provided
// like a forwarding one for emplacing, but I am going for minimal here
clonable_holder(Derived value)
: storage(std::move(value)) {}
// here we know the most derived type, so we can use the copy constructor
// without risk of slicing
std::unique_ptr<clonable<Base>> clone() const override {
return std::unique_ptr<clonable<Base>>(new clonable_holder(storage));
}
Base* get() override { return &storage; }
Base const* get() const override { return &storage; }
private:
Derived storage;
};
Run Code Online (Sandbox Code Playgroud)
这将为我们生成虚拟复制功能,而无需额外的样板.现在我们可以在此基础上构建一个类似智能指针的类(不是一个智能指针,因为它不提供指针语义,而是提供值语义).
template <typename Base>
struct polymorphic_value {
// this constructor captures the most derived type and erases it
// this is a point where slicing may still occur
// so making it explicit may be desirable
// we could force constructions through a forwarding factory class for extra safety
template <typename Derived>
polymorphic_value(Derived value)
: handle(new clonable_holder<Base, Derived>(std::move(value))) {
static_assert(std::is_base_of<Base, Derived>::value,
"value must be derived from Base");
}
// moving is free thanks to unique_ptr
polymorphic_value(polymorphic_value&&) = default;
polymorphic_value& operator=(polymorphic_value&&) = default;
// copying uses our virtual interface
polymorphic_value(polymorphic_value const& that)
: handle(that.handle->clone()) {}
polymorphic_value& operator=(polymorphic_value const& that) {
handle = that.handle->clone();
return *this;
}
// other useful constructors involve upcasting and so on
// and then useful stuff for actually using the value
Base* operator->() { return handle.get(); }
Base const* operator->() const { return handle.get(); }
// ...
private:
std::unique_ptr<clonable<Base>> handle;
};
Run Code Online (Sandbox Code Playgroud)
这只是一个最小的界面,但它可以很容易地从这里充实,以涵盖更多的使用场景.
虽然有点晚了,但对于未来的观众来说:我的纯标头库Aurora及其SmartPtr 教程中有一个现成的实现。有了Aurora,通过智能指针实现深度复制就变得很简单。以下代码适用于任何可复制类型T:
aurora::CopiedPtr<T> first(new T);
aurora::CopiedPtr<T> second = first; // deep copy
Run Code Online (Sandbox Code Playgroud)
如果您的类具有指针成员,则通常无需实现“三巨头”/“五巨头”。