shared_ptr魔术:)
Lidström先生和我有一个观点 🙂
Lidström先生的说法是构造shared_ptr<Base> p(new Derived);
不需要Base有一个虚拟析构函数:
Armen Tsirunyan :“真的吗? shared_ptr能够正确清理吗?在这种情况下,请您certificate这个效果如何实现?
DanielLidström :“ shared_ptr使用自己的析构函数来删除具体的实例,这在C ++社区中被称为RAII,我的build议是你可以学习关于RAII的所有知识,当你使用C ++时, RAII在所有情况下。“
Armen Tsirunyan :“我知道RAII,而且我也知道,当pn达到0时, shared_ptr析构函数最终可能会删除存储的px。但是,如果px具有指向
Base
静态types指针和指向Derived
dynamictypes指针,则除非Base
具有虚拟析构函数,这会导致不确定的行为,如果我错了,纠正我。DanielLidström :“ shared_ptr知道静态types是Concrete,它知道这个,因为我在构造函数中传递它,看起来有点像魔术,但我可以向你保证它是有devise的,非常好。
所以,评判我们。 怎么可能(如果是的话)实现shared_ptr而不要求多态类具有虚拟析构函数? 提前致谢
是的,可以通过这种方式来实现shared_ptr。 Boost和C ++ 11标准也需要这种行为。 作为一个附加的灵活性,shared_ptrpipe理的不仅仅是一个参考计数器。 通常将所谓的删除器放入同样包含参考计数器的内存块中。 但有趣的是,这个删除器的types不是shared_ptrtypes的一部分。 这被称为“types擦除”,基本上是用于实现“多态函数”boost :: function或std :: function用于隐藏实际函子types的技术。 为了使你的例子工作,我们需要一个模板化的构造函数:
template<class T> class shared_ptr { public: ... template<class Y> explicit shared_ptr(Y* p); ... };
所以,如果你用你的类Base和Derived …
class Base {}; class Derived : public Base {}; int main() { shared_ptr<Base> sp (new Derived); }
… Y = Derived的模板化构造函数用于构造shared_ptr对象。 因此,构造函数有机会创build适当的删除对象和引用计数器,并将指向此控制块的指针存储为数据成员。 如果引用计数器达到零,则将使用先前创build的Derived-aware删除器来处理该对象。
C ++ 11标准对此构造函数(20.7.2.2.1)有如下说明:
要求:
p
必须转换为T*
。Y
应该是一个完整的types。delete p
expression式应当形成良好,行为明确,不得抛出exception。效果:构造一个拥有指针
p
的shared_ptr
对象。…
而对于析构函数(20.7.2.2.2):
影响:如果
*this
为空或与另一个shared_ptr
实例(use_count() > 1
)共享所有权,则不会有副作用。 否则,如果*this
拥有一个对象p
和一个删除器d
,则调用d(p)
。 否则,如果*this
拥有一个指针p
,并且调用delete p
。
(强调使用粗体是我的)。
当创buildshared_ptr时,它会在其内部存储一个deleter对象。 当shared_ptr即将释放指向的资源时,将调用此对象。 既然你知道如何在构造的时候破坏资源,你可以使用shared_ptrtypes不完整。 无论谁创buildshared_ptr都存储了正确的删除者。
例如,您可以创build一个自定义删除器:
void DeleteDerived(Derived* d) { delete d; } // EDIT: no conversion needed. shared_ptr<Base> p(new Derived, DeleteDerived);
p将调用DeleteDerived来销毁指向的对象。 该实现自动执行此操作。
只是,
shared_ptr
使用由构造函数创build的特殊的删除函数,该函数始终使用给定对象的析构函数,而不是Base的析构函数,这与模板元编程有点相似,但是起作用。
就是这样
template<typename SomeType> shared_ptr(SomeType *p) { this->destroyer = destroyer_function<SomeType>(p); ... }