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指针和指向Deriveddynamictypes指针,则除非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 pexpression式应当形成良好,行为明确,不得抛出exception。

效果:构造一个拥有指针pshared_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); ... }