【问题标题】:Why does enable_shared_from_this have a non-virtual destructor?为什么 enable_shared_from_this 有一个非虚拟析构函数?
【发布时间】:2011-02-04 00:54:03
【问题描述】:

我有一个宠物项目,我用它来试验 C++11 的新特性。虽然我有 C 方面的经验,但我对 C++ 还是很陌生。为了训练自己掌握最佳实践(除了大量阅读),我启用了一些严格的编译器参数(使用 GCC 4.4.1):

-std=c++0x -Werror -Wall -Winline -Weffc++ -pedantic-errors

这对我来说效果很好。到现在为止,我已经能够解决所有的障碍。但是,我需要enable_shared_from_this,这给我带来了问题。在编译我的代码(可能由-Weffc++ 触发)时,我收到以下警告(在我的情况下是错误):

base class ‘class std::enable_shared_from_this<Package>’ has a non-virtual destructor

所以基本上,我对enable_shared_from_this 的这种实现有点困扰,因为:

  • 旨在用于子类化的类的析构函数应该始终是虚拟的,恕我直言。
  • 析构函数是空的,为什么还要它?
  • 我无法想象有人会想通过引用 enable_shared_from_this 来删除他们的实例。

但我正在寻找解决这个问题的方法,所以我的问题是,真的有合适的方法来处理这个问题吗?并且:我认为这个析构函数是假的是否正确,或者它有真正的目的?

【问题讨论】:

  • 您尝试过私有继承还是受保护继承?它会改变诊断吗?
  • 这是个好主意。但不幸的是,它没有。
  • -Weffc++ 会从标准库中触发很多无意义的(与库有关的)警告,这在in the FAQ 中被提及

标签: c++ gcc boost c++11 shared-ptr


【解决方案1】:

用于子类化的类的析构函数应该始终是虚拟的,恕我直言。

只有当派生类的实例通过指向基类的指针被删除时,才需要基类中的虚拟析构函数。

在类中包含任何虚函数,包括析构函数,都需要开销。 Boost(以及 TR1 和 C++11 标准库)不希望仅仅因为您需要能够从 this 指针获取 shared_ptr 就强迫您拥有这种开销。

析构函数是空的,为什么有呢?

如果你没有用户定义的构造函数,编译器会为你提供一个,所以没关系。

我无法想象有人会想通过引用 enable_shared_from_this 来删除他们的实例。

没错。

至于编译器警告,我会忽略警告或禁止它(在代码中添加注释来解释您这样做的原因)。有时,尤其是在“学究式”警告级别,编译器警告无济于事,我会说这是其中一种情况。

【讨论】:

  • 不幸的是,使用 g++ 我们必须为整个类关闭该警告...这意味着您不会遇到其他潜在问题(包括未初始化变量成员等潜在错误。)
【解决方案2】:

我同意 James 的描述,但会补充

只有当您想虚拟地销毁该类的实例时,才需要虚拟析构函数。情况并非总是如此,但是如果一个基类不打算被虚拟销毁,它应该防止它发生

所以我会改变

类的析构函数 用于子类化的应始终 是虚拟的,恕我直言。

这是:

类的析构函数 用于子类化应该 始终是虚拟的受保护的

【讨论】:

  • 嗯..好点。 enable_shared_from_this 的析构函数实际上是受保护的。所以也许这是 GCC 的 -Weffc++ 中的一个错误?
  • @Shtééf:Effective C++ 说,多态基应该有虚拟 dtor,不打算用于多态的类不应该有虚拟 dtor。由于编译器无法分辨哪个是哪个,我会说是的,提供此警告是一个错误。因此,如果来自 GotW / Exceptional C++,则您对 IIRC 的实现是关于非多态基类中受保护的 dtor 的建议,而不是有效的。
  • 此外,我的 gcc 手册页版本说 -Wnon-virtual-dtor 警告仅适用于具有虚函数的类。所以enable_shared_from_this 有一个虚函数(我的实现没有),或者警告没有遵循文档(这将是一个错误),或者文档已经改变(检查你的,也许他们解释了警告进一步)。实际上,Effective C++ 可能已更新 - gcc 手册页引用的标题与我的第 3 版不匹配。所以可以说这是 Scott Meyers 书中的一个错误 ;-)
  • enable_shared_from_this 没有虚函数,但如果派生类有虚函数,GCC 会发出警告,而不仅仅是基类有虚函数。 -Weffc++ 有很多已知的缺陷,包括项目编号指的是书籍的旧版本,其中一些项目已被删除或重写以用于以后的版本,并且警告尚未更新,在某些情况下它会发出警告style 不正确,它并不总是有用的。 -Wdelete-non-virtual-dtor 选项(起源于 Clang,我添加到 G++ 中)比 -Wnon-virtual-dtor 更有用
【解决方案3】:

有没有合适的方法来处理这个问题?

不要一直使用-Weffc++。有时打开它以检查您的代码很有用,但并不是真正永久使用它。它会产生误报,并且这些天并没有真正维护。不时使用它,但请注意您可能不得不忽略一些警告。理想情况下,只需记住 Meyers 书中的所有建议,然后你就不需要它了 ;-)

我认为这个析构函数是假的是正确的,还是它有真正的目的?

不,这不是伪造的,并且有真正的目的。 如果它没有被定义,它将被隐式声明为public,以防止它被显式声明为protected

【讨论】:

    猜你喜欢
    • 2015-11-12
    • 2020-11-11
    • 2020-03-06
    • 2014-02-12
    • 2010-12-11
    • 2016-12-28
    • 2012-01-31
    • 2021-07-17
    • 1970-01-01
    相关资源
    最近更新 更多