C++ 共享\u ptr魔法:)
:) Lidström先生的主张是,一个结构C++ 共享\u ptr魔法:),c++,destructor,smart-pointers,C++,Destructor,Smart Pointers,:) Lidström先生的主张是,一个结构共享ptr p(新派生)不要求Base具有虚拟析构函数: Armen Tsirunyan:“真的吗?共享的ptr会正确清理吗?在这种情况下,你能演示一下如何实现这种效果吗?” < Daniel Lidstr >μ>强:“SyddypTR使用它自己的析构函数删除具体实例。这在C++社区中被称为RAII。我的建议是,您可以了解RAII的所有内容。当您在所有情况下使用RAII时,它将使您的C++编码变得更容易。” 阿门·齐鲁尼亚:“我知道RAII,我也知道
共享ptr p(新派生)代码>不要求Base具有虚拟析构函数:
Armen Tsirunyan:“真的吗?共享的ptr会正确清理吗?在这种情况下,你能演示一下如何实现这种效果吗?”
< Daniel Lidstr >μ>强:“SyddypTR使用它自己的析构函数删除具体实例。这在C++社区中被称为RAII。我的建议是,您可以了解RAII的所有内容。当您在所有情况下使用RAII时,它将使您的C++编码变得更容易。”
阿门·齐鲁尼亚:“我知道RAII,我也知道最终共享的解构器可能会在pn达到0时删除存储的px。但是如果px有指向
Base
的静态类型指针和指向派生的的动态类型指针,那么除非Base
有一个虚拟析构函数,否则这将导致未定义的行为。如果我错了,请纠正我。”
Daniel Lidström:“共享ptr知道静态类型是具体的。它知道这一点,因为我在它的构造函数中传递了它!看起来有点像魔术,但我可以向你保证它是精心设计的,非常漂亮。”
那么,判断一下我们,在不要求多态类具有虚拟析构函数的情况下,如何实现共享的_ptr呢?
提前感谢简单地说
shared_ptr
使用特殊的deleter函数,该函数由始终使用
给定对象的析构函数,而不是Base的析构函数,这是模板元编程的一点工作,但它可以工作
诸如此类
template<typename SomeType>
shared_ptr(SomeType *p)
{
this->destroyer = destroyer_function<SomeType>(p);
...
}
模板
共享ptr(SomeType*p)
{
该->销毁程序=销毁程序功能(p);
...
}
简单地说
shared_ptr
使用特殊的deleter函数,该函数由始终使用
给定对象的析构函数,而不是Base的析构函数,这是模板元编程的一点工作,但它可以工作
诸如此类
template<typename SomeType>
shared_ptr(SomeType *p)
{
this->destroyer = destroyer_function<SomeType>(p);
...
}
模板
共享ptr(SomeType*p)
{
该->销毁程序=销毁程序功能(p);
...
}
创建共享\u ptr时,它会在自身内部存储一个删除器对象。当共享\u ptr即将释放指向的资源时,会调用此对象。因为您知道如何在构建时销毁资源,所以可以使用类型不完整的共享\u ptr。创建共享\u ptr的人会在其中存储正确的删除器
例如,您可以创建自定义删除器:
void DeleteDerived(Derived* d) { delete d; } // EDIT: no conversion needed.
shared_ptr<Base> p(new Derived, DeleteDerived);
void delete派生(派生*d){delete d;}//编辑:无需转换。
共享_ptr p(新派生、删除派生);
p将调用DeleteDerived来销毁指向的对象。实现会自动执行此操作。创建共享\u ptr时,它会在自身内部存储一个deleter对象。当共享\u ptr即将释放指向的资源时,会调用此对象。因为您知道如何在构建点销毁资源,所以可以使用共享类型不完整的d_ptr。创建共享_ptr的人在其中存储了正确的删除器
例如,您可以创建自定义删除器:
void DeleteDerived(Derived* d) { delete d; } // EDIT: no conversion needed.
shared_ptr<Base> p(new Derived, DeleteDerived);
void delete派生(派生*d){delete d;}//编辑:无需转换。
共享_ptr p(新派生、删除派生);
p将调用DeleteDerived来销毁指向的对象。实现会自动执行此操作。是的,可以通过这种方式实现shared_ptr。Boost会这样做,C++11标准也要求这种行为。作为一种附加的灵活性,shared_ptr管理的不仅仅是一个引用计数器。所谓的deleter通常被放入同一个内存块也包含引用计数器。但有趣的是,此删除器的类型不是共享\u ptr类型的一部分。这称为“类型擦除”,基本上与用于实现“多态函数”的技术相同“boost::function或std::function用于隐藏实际函子的类型。为了使您的示例正常工作,我们需要一个模板化构造函数:
template<class T>
class shared_ptr
{
public:
...
template<class Y>
explicit shared_ptr(Y* p);
...
};
模板
类共享\u ptr
{
公众:
...
模板
显式共享ptr(Y*p);
...
};
所以,如果你把它用于你的基类和派生类
class Base {};
class Derived : public Base {};
int main() {
shared_ptr<Base> sp (new Derived);
}
类基{};
派生类:公共基{};
int main(){
共享ptr sp(新衍生);
}
。。。Y=Derived的模板化构造函数用于构造共享的\u ptr对象。因此,构造函数有机会创建适当的删除器对象和引用计数器,并将指向此控制块的指针存储为数据成员。如果引用计数器达到零,则将使用先前创建和派生的aware deleter来处理该对象
C++11标准对该构造函数(20.7.2.2.1)有如下说明:
要求:p
必须可转换为T*
<代码>Y
应为完整类型表达式delete p
应格式良好,具有明确的行为,且不得引发异常。
效果:构造一个共享的\u ptr
对象,该对象拥有指针p
对于析构函数(20.7.2.2.2):
效果:如果*此
为空或与另一个共享的\u ptr
实例共享所有权(使用\u count()>1
),则没有副作用。
否则,如果*此
拥有对象p
和删除器d
,则调用d(p)
。
否则,如果*此
拥有指针p
,则调用delete p
。
(我用粗体强调)。是的,用这种方式实现共享ptr是可能的。Boost确实如此,C++11标准也要求这种行为。作为一种额外的灵活性,shared_ptr不仅仅管理一个参考计数器。通常将所谓的删除器放入