Arm*_*yan 82 c++ destructor smart-pointers
Lidström先生的主张是,构造shared_ptr<Base> p(new Derived);
不要求Base有虚拟析构函数:
Armen Tsirunyan:"真的吗?shared_ptr会正确清理吗?在这种情况下你能否证明可以实现这种效果?"
DanielLidström:" shared_ptr使用自己的析构函数来删除Concrete实例.这在C++社区中被称为RAII.我的建议是你学习RAII的全部内容.它将使你的C++编码在使用时更加容易RAII在所有情况下."
Armen Tsirunyan:"我知道RAII,我也知道,当pn达到0时,最终shared_ptr析构函数可能会删除存储的px.但是如果px有静态类型指针
Base
和动态类型指针Derived
,那么除非Base
有一个虚拟析构函数,会导致不确定的行为.如果我错了,请纠正我."DanielLidström:" shared_ptr知道静态类型是Concrete.它知道这个,因为我在它的构造函数中传递它!看起来有点像魔术,但我可以向你保证它是设计上的并且非常好."
所以,判断我们.如何实现shared_ptr而不需要多态类具有虚拟析构函数是否可能(如果是)?提前致谢
sel*_*tze 70
是的,可以通过这种方式实现shared_ptr.Boost确实如此,C++ 11标准也需要这种行为.作为一种额外的灵活性,shared_ptr管理的不仅仅是参考计数器.通常将所谓的删除器放入同样包含参考计数器的存储器块中.但有趣的是,此删除器的类型不是shared_ptr类型的一部分.这称为"类型擦除",基本上与用于实现"多态函数"boost :: function或std :: function以隐藏实际仿函数类型的技术相同.为了使您的示例有效,我们需要一个模板化的构造函数:
template<class T>
class shared_ptr
{
public:
...
template<class Y>
explicit shared_ptr(Y* p);
...
};
Run Code Online (Sandbox Code Playgroud)
所以,如果你在你的类Base和Derived中使用它...
class Base {};
class Derived : public Base {};
int main() {
shared_ptr<Base> sp (new Derived);
}
Run Code Online (Sandbox Code Playgroud)
...使用Y = Derived的模板化构造函数用于构造shared_ptr对象.因此,构造函数有机会创建适当的删除对象和引用计数器,并将指向该控制块的指针存储为数据成员.如果引用计数器达到零,则将使用先前创建的和Derived-aware删除器来处置该对象.
关于这个构造函数(20.7.2.2.1),C++ 11标准有以下内容:
要求:
p
必须可转换为T*
.Y
应该是一个完整的类型.表达式delete p
应格式良好,具有明确的行为,不得抛出异常.效果:构造一个
shared_ptr
对象是拥有指针p
....
对于析构函数(20.7.2.2.2):
效果:如果
*this
为空或与另一个shared_ptr
实例共享所有权(use_count() > 1
),则没有副作用.否则,如果*this
拥有一个对象p
和一个删除器d
,d(p)
则被调用. 否则,如果*this
拥有一个指针p
,delete p
则被调用.
(强调使用粗体字是我的).
ybu*_*ill 28
创建shared_ptr时,它会在自身内部存储一个删除对象.当shared_ptr即将释放指向的资源时,将调用此对象.由于您知道如何在构造点销毁资源,因此可以将shared_ptr用于不完整类型.创建shared_ptr的人在那里存储了正确的删除器.
例如,您可以创建自定义删除器:
void DeleteDerived(Derived* d) { delete d; } // EDIT: no conversion needed.
shared_ptr<Base> p(new Derived, DeleteDerived);
Run Code Online (Sandbox Code Playgroud)
p将调用DeleteDerived来销毁指向的对象.实现会自动执行此操作.
Art*_*yom 16
只是,
shared_ptr
使用由构造函数创建的特殊删除函数,该函数总是使用给定对象的析构函数而不是Base的析构函数,这对模板元编程有一些作用,但它有效.
这样的事情
template<typename SomeType>
shared_ptr(SomeType *p)
{
this->destroyer = destroyer_function<SomeType>(p);
...
}
Run Code Online (Sandbox Code Playgroud)