为了账号安全,请及时绑定邮箱和手机立即绑定

shared_ptr魔术:)

shared_ptr魔术:)

C++
扬帆大鱼 2019-10-06 13:11:15
Lidström先生的主张是,构造shared_ptr<Base> p(new Derived);不需要Base具有虚拟析构函数:Armen Tsirunyan:“真的吗?shared_ptr会正确清理吗?在这种情况下,请您演示一下如何实现这种效果?”DanielLidström:“ shared_ptr使用其自己的析构函数来删除具体实例。在C ++社区中,这被称为RAII。我的建议是,您将学习到有关RAII的全部知识。它将使您使用C ++的代码如此容易在任何情况下都可以使用RAII。”Armen Tsirunyan:“我了解RAII,而且我也知道,最终pn到达0时,shared_ptr析构函数可能会删除存储的px。但是,如果px具有指向的静态类型指针Base和动态类型的指针Derived,则除非Base具有虚拟析构函数,否则会导致不确定的行为。如果我做错了,请纠正我。”DanielLidström:“ shared_ptr知道静态类型是Concrete。自从我在其构造函数中传递它以来,它就知道这一点!看起来有点像魔术,但是我可以向您保证,它是设计使然,非常好。”所以,判断我们。在不要求多态类具有虚拟析构函数的情况下,如何(如果可能)实现shared_ptr?提前致谢
查看完整描述

3 回答

?
达令说

TA贡献1821条经验 获得超6个赞

是的,可以通过这种方式实现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);

   ...

};

因此,如果您将其与Base和Derived类一起使用,则...


class Base {};

class Derived : public Base {};


int main() {

   shared_ptr<Base> sp (new Derived);

}

...具有Y = Derived的模板化构造函数用于构造shared_ptr对象。因此,构造函数有机会创建适当的删除对象和引用计数器,并将指向该控制块的指针存储为数据成员。如果参考计数器达到零,则将使用先前创建的可感知派生的删除器来处置该对象。


关于此构造函数(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和一个deleteer d,d(p)则被调用。 否则,如果*this拥有一个指针p,delete p则被调用。


(强调使用粗体是我的)。


查看完整回答
反对 回复 2019-10-06
?
喵喵时光机

TA贡献1846条经验 获得超7个赞

创建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);

p将调用DeleteDerived销毁指向的对象。该实现会自动执行此操作。


查看完整回答
反对 回复 2019-10-06
?
ABOUTYOU

TA贡献1812条经验 获得超5个赞

只是,


shared_ptr 使用由构造函数创建的特殊删除函数,该函数始终使用给定对象的析构函数而不是Base的析构函数,这与模板元编程有关,但确实可行。


像这样


template<typename SomeType>

shared_ptr(SomeType *p)

{

   this->destroyer = destroyer_function<SomeType>(p);

   ...

}


查看完整回答
反对 回复 2019-10-06
  • 3 回答
  • 0 关注
  • 411 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信