【问题标题】:Why is it fine to use Boost.Intrusive containers to store polymorphic objects?为什么可以使用 Boost.Intrusive 容器来存储多态对象?
【发布时间】:2018-08-20 06:15:51
【问题描述】:

这是一个经常重复的建议,即不应从具有非虚拟析构函数的类继承(如果打算使用动态多态性)。这就是为什么从标准容器类继承被认为是一个坏主意的原因。

另一方面,Boost.Intrusive 明确地states 表示它的容器适合存储多态对象。在链接的示例中,这是通过派生自 boost::intrusive::list_base_hook<> 来实现的,该 boost::intrusive::list_base_hook<> 没有虚拟析构函数,并且仅在派生类中引入一个。

  1. 这是一个有效的设计吗?
  2. 如果是这样,它为什么以及如何符合我上面提到的一般建议?特别是,为什么不能用相同的逻辑证明从标准容器继承?

(请注意,我的问题不是关于标准容器和 Boost.Intrusive 容器之间的区别。我对正确使用 Boost.Intrusive 很感兴趣,但我仅将标准容器作为示例提及,因为它们经常在出现类似主题时出现讨论过。)

【问题讨论】:

    标签: c++ boost polymorphism


    【解决方案1】:

    只有当派生类的使用涉及通过指向基类的指针对对象的所有权时,才不应从具有非虚拟析构函数的类继承。标准容器类没有什么特别之处。从它们继承并不是一个坏主意,但问题是应该首选其他扩展其功能的方法:添加独立函数或聚合。

    boost::intrusive::list_base_hook<> 派生是一个完全有效的设计,因为派生对象的所有权永远不会通过指向list_base_hook 的指针来持有。请注意,库通过聚合提供挂钩(使用list_member_hook),这应该优于继承。

    【讨论】:

    • 通过基类指针的所有权和多态销毁std::shared_ptr,例如,在构造时类型擦除并存储指针的析构函数,因此不需要虚拟析构函数来工作。
    • @Quentin 不幸的是,shared_ptr 没有魔法,它只能正确地获取指向派生类对象的指针的所有权。 Base * const naked_p_base{new Derived{}}; ::std::shared_ptr<Base> p_base{naked_p_base}; 已损坏,除非 Base 析构函数是虚拟的或提供了适当的删除器。
    • 当然,但我确实说过“在构造时”——就像在 C++ 中一样,你可以不遗余力地破坏东西,但如果你像文明人一样使用std::make_unique,一切都会没事:)
    • 我知道会员挂钩。为什么你说它们应该优先于基础钩子?据我所知,文档没有说这样的话。事实上,“使用成员钩子”here 下的最后一段似乎完全相反,尤其是在多态性的上下文中。
    • @VTT 关于成员钩子应该优先于基本钩子,这实际上不是真的。成员钩子在 Boost.Intrusive 中需要不可移植的实现,虽然对于大多数广泛使用的编译器都提供了工作实现(搜索 offset_from_pointer_to_member),但它仍然不可移植,并且在某些情况下可能会中断。底座挂钩没有这个问题,应该是便携的。
    猜你喜欢
    • 1970-01-01
    • 2011-02-15
    • 1970-01-01
    • 2013-08-24
    • 2015-04-30
    • 1970-01-01
    • 2020-01-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多