【问题标题】:Why are destructors not virtual by default [C++]为什么析构函数默认不是虚拟的[C++]
【发布时间】:2011-09-30 22:24:36
【问题描述】:

为什么 C++ 默认情况下不让析构函数为虚拟对于至少有一个其他虚函数的类?在这种情况下,添加一个虚拟析构函数不会花费我任何成本,而没有一个是(几乎? ) 总是一个错误。 C++0x 会解决这个问题吗?

【问题讨论】:

  • 关键字是almost。如果您的基础具有虚拟功能并且您不想为虚拟析构函数付费,那么您如何在这个新世界中指定它不是虚拟的。所有旧代码也会发生什么?我们需要一个计划来处理向后兼容性问题。
  • 虚拟析构函数是有代价的,因为它需要另一个析构函数代码副本,用于所有派生类。见this question
  • @Simon,不过,D0 变体可以实现为 D1 的包装器。
  • 不可能重复,我明白为什么并非所有函数默认都是虚拟的。我的问题是,为什么 C++ 在您声明另一个函数为虚拟时,默认情况下不将析构函数设为虚拟。

标签: c++ virtual-destructor


【解决方案1】:

您无需为不需要的东西付费。如果你从不通过基指针删除,你可能不想要间接析构函数调用的开销。

也许您认为 vtable 的存在是唯一的开销。但是也必须考虑每个单独的函数调度,如果我想直接调度我的析构函数调用,我应该被允许这样做。

如果你确实删除了一个基指针并且那个类有虚方法,我想你的编译器会很好地警告你。

编辑: 让我在这里引用 Simon 的出色评论:查看 this SO question 为析构函数生成的代码。如您所见,还需要考虑代码膨胀开销。

【讨论】:

    【解决方案2】:

    这是一个例子(我不建议编写这样的代码):

    struct base {
        virtual void foo() const = 0;
        virtual void bar () const = 0;
    };
    
    struct derived: base {
        void foo() const {}
        void bar() const {}
    };
    
    std::shared_ptr<base>
    make_base()
    {
        return std::make_shared<derived>();
    }
    

    这是没有显示 UB 的完美代码。这是可能的,因为std::shared_ptr 使用类型擦除;对delete 的最终调用将删除derived*,即使最后一个触发销毁的std::shared_ptrstd::shared_ptr&lt;void&gt; 类型。

    请注意,std::shared_ptr 的这种行为不是为虚拟销毁量身定做的;它有多种其他用途(例如std::shared_ptr&lt;FILE&gt; { std::fopen( ... ), std::fclose })。然而,由于这种技术已经支付了一些间接工作的成本,一些用户可能对为他们的基类使用虚拟析构函数不感兴趣。这就是“只为你需要的东西付费”的意思。

    【讨论】:

      【解决方案3】:

      按照标准的规定,具有非虚拟析构函数的多态类不是错误。对此类对象执行的一项特定操作会导致未定义的行为,但其他一切都是完美的。那么考虑到标准在允许程序员犯什么错误方面的宽松行为,为什么要对析构函数给予特殊处理?

      这样的改变会产生一些成本,尽管大部分都是微不足道的:虚拟表将大一个元素,并且虚拟调度与析构函数调用相关联。

      据我所知,不,C++11 中的析构函数在这方面的行为没有变化。我想它会在关于特殊成员函数的部分中说些什么,但它没有,而且在一般的虚函数部分中同样没有任何内容。

      【讨论】:

      • 是否有曾经计划将虚拟析构函数设为 C++0x 中的默认值?我之所以问是因为我看到了这篇论文:www2.research.att.com/~bs/C++0x_panel.pdf,上面说有在底部,但我找不到更多关于它的信息。
      • @dacode:我没有关注实际的会议等等,所以我不知道。四个“尴尬”中,只有最后一个真正被改变了。如果有人提交了这样一个改变的提案,我不会感到惊讶,但我不能说为什么它被否决了。
      猜你喜欢
      • 2012-11-03
      • 2010-10-24
      • 2015-11-12
      • 1970-01-01
      • 2011-10-29
      • 2021-08-22
      • 2017-04-21
      • 2021-12-09
      • 2014-01-30
      相关资源
      最近更新 更多