Lidström 先生声称构造 shared_ptr<Base> p(new Derived);
不需要 Base 具有虚拟析构函数:
Armen Tsirunyan :“真的吗? shared_ptr 会正确清理吗?你能在这种情况下演示如何实现这种效果吗?”
Daniel Lidström :“ shared_ptr 使用它自己的析构函数来删除 Concrete 实例。这在 C++ 社区中被称为 RAII。我的建议是你尽可能了解 RAII。当你使用它时,它会让你的 C++ 编码变得更加容易所有情况下的 RAII。”
Armen Tsirunyan :“我知道 RAII,我也知道最终 shared_ptr 析构函数可能会在 pn 达到 0 时删除存储的 px。但是如果 px 有指向
Base
的静态类型指针和指向Derived
,那么除非Base
具有虚拟析构函数,这将导致未定义的行为。如果我错了,请纠正我。Daniel Lidström :“ shared_ptr 知道静态类型是 Concrete。它知道这一点,因为我在它的构造函数中传递了它!看起来有点像魔术,但我可以向你保证,它是设计使然,非常好。”
所以,评判我们。如何在不需要多态类具有虚拟析构函数的情况下实现 shared_ptr (如果是的话)?提前致谢
原文由 Armen Tsirunyan 发布,翻译遵循 CC BY-SA 4.0 许可协议
是的,可以这样实现 shared_ptr 。 Boost 确实如此,C++11 标准也需要这种行为。作为一个额外的灵活性,shared_ptr 管理的不仅仅是一个引用计数器。所谓的删除器通常被放入同样包含引用计数器的内存块中。但有趣的是这个删除器的类型不是 shared_ptr 类型的一部分。这称为“类型擦除”,与用于实现“多态函数”
boost::function
或std::function
用于隐藏实际函子类型的技术基本相同。为了使您的示例工作,我们需要一个模板化的构造函数:所以,如果你在你的课程中使用它
Base
和Derived
……带有
Y=Derived
的模板化构造函数用于构造shared_ptr
对象。因此,构造函数有机会创建适当的删除器对象和引用计数器,并将指向该控制块的指针存储为数据成员。如果引用计数器达到零,则先前创建的和Derived
删除器将用于处理对象。C++11 标准对这个构造函数 (20.7.2.2.1) 有以下说法:
对于析构函数(20.7.2.2.2):
(强调使用粗体是我的)。