假设我们有一个base
类和一个derived
。所以:
class base {
protected:
~base(){
//...
}
// ...
};
class derived : public base {
// ...
};
现在,我们使用上面的类和智能指针类来编写此代码:
SmartPointer<base> bptr(new derived());
delete bptr;
我知道它会通过调用
derived
的析构函数来阻止derived
对象的切片,但是它怎么知道这样做呢?存储在智能指针中的引用不是base*
类型的引用吗?它是否遍历某种层次结构树,将该指针转换为derived*
,然后调用delete?还是还有其他我不知道的事情?据称该实现是线程安全的,非侵入式的和引用计数的。
是,您看到的类类似于我正在测试的类。显然,使用THESE GIVEN类可以做到这一点。在上面的问题中提到了有关如何操作的主要思想,但是我不确定这样的实现将如何工作。
最佳答案
第一件事是,按原样,该代码将无法正常工作。 base
的析构函数至少必须是protected
(或派生类是基础的 friend )。 private
析构函数意味着编译器不允许您为派生类编写析构函数。现在,假设您有一个protected
析构函数...(记住,如果您设计要扩展的类,请提供一个公共(public)虚拟析构函数或一个 protected 非虚构函数!)
一切都取决于SmartPointer
的实现,特别是std::shared_ptr
(或增强版对应的boost::shared_ptr
)能够干净地管理这种情况。该解决方案执行某种类型的部分类型擦除,以实现销毁目的。基本上,智能指针具有模板化的构造函数,该构造函数接受可以分配给base
指针的任何指针,但是由于它是模板化的,因此它知 Prop 体的类型。那时,它存储了一个合成的deleter
函数,该函数将调用适当的析构函数。
为简单起见,请使用std::function
:
template <typename T>
void delete_deleter( void * p ) {
delete static_cast<T*>(p);
}
template <typename T>
class shared_pointer {
T * ptr;
std::function<void(void*)> deleter;
public:
template <typename U>
shared_pointer( U* p, std::function<void()> d = delete_deleter<U> )
: ptr(p), deleter(d)
{}
~shared_pointer() {
deleter( ptr ); // call the stored destructor
}
};
该代码仅用于展示,必须对其进行调整以进行生产(在哪里存储
function
,引用计数...),但这足以给您一个想法:在唯一的函数中,对象的确切类型是已知的(在创建智能指针时),您将创建一个包装器,该包装器将调用所需的析构函数的确切版本(提供某种类型的擦除),然后将其保留下来,并在需要对对象进行delete
调用时将其调用而不是delete
运算符。这也可以用于管理其他需要调用特殊方法而不是
delete
的资源:// exhibition only!
shared_pointer<Foo> p( Factory.create(), &Factory::release );
同样,在准备好生产之前,应该做很多工作。
可以从问题中消除对用于简化擦除操作的
std::function
的依赖性。在简单的情况下(智能指针仅支持分配了new
并释放了delete
的内存),然后只需提供一个带有单个虚拟deleter
的operator()(void*)
基类,然后将现有delete_deleter
重构为覆盖deleter
的operator()(void*)
的模板化派生类与当前的实现。如果您需要处理一般情况(保留任何类型的资源),这是不值得的,只需使用std::function
或boost::function
即可。