【问题标题】:Does 'final' specifier add any overhead?'final' 说明符会增加任何开销吗?
【发布时间】:2015-08-12 14:12:22
【问题描述】:

classfunction 上使用说明符final 会增加任何内存或cpu 开销,还是仅在编译时使用?

std::is_final 如何识别什么是最终的?

【问题讨论】:

标签: c++ c++11 c++14


【解决方案1】:

它实际上可以减少开销。在极少数情况下,增加它。

如果您有一个指向finalA 的指针,则可以对任何虚拟方法调用进行去虚拟化并直接调用。类似地,对虚拟final 方法的调用可以被去虚拟化。另外,一个final类的继承树是固定的,即使它包含virtual父类,所以你可以去虚拟化一些父访问。

这些去虚拟化中的每一个都减少或消除了查询运行时结构(vtable)的要求。

可能会有轻微的不利影响。一些编码技术依靠 vtable 访问来避免直接访问符号,然后不导出符号。访问 vtable 可以通过约定来完成(没有库中的符号,只有相关类的头文件),而直接访问方法涉及到链接到该符号。

这打破了动态 C++ 库链接的一种形式(避免链接超过 dll 加载符号和/或返回指针的 C 链接函数,并且类通过其 vtable 导出)。

如果您链接到动态库中的符号,动态库符号加载也可能比 vtable 查找更昂贵。我没有经历过或描述过这一点,但我已经看到它声称。一般来说,收益应该超过这些成本。任何此类成本都是实施质量问题,因为方法是final,因此成本不是强制性的。

最后,final 禁止对类进行空基优化技巧,其中有人知道您的类没有状态,并从它继承以减少将类实例从 1 字节“存储”到 0 字节的开销。如果您的类是空的并且不包含虚拟方法/继承,请不要使用final 以避免被阻止。 final 函数没有等价物。

除了 EBO 优化问题(只发生在空类型上)之外,final 的任何开销都来自其他代码与它的交互方式,并且很少见。更常见的是,它会使其他代码更快,因为直接与方法交互可以更直接地调用方法,并且可以导致连锁优化(因为编译器可以更充分地理解调用)。

当它是 final 时,将除空类型之外的任何东西标记为 final 在运行时几乎可以肯定是无害的。对具有虚函数和继承的类这样做在运行时可能是有益的。


std::is_final 和类似的特征几乎都是通过编译器内置的魔法实现的。 std 中的许多特征都需要这种魔法。见How to detect if a class is final in C++11?(感谢@Csq 发现)

【讨论】:

  • @TemplateRex EBO 悲观?您不能对最终类使用空基优化,因为您不能从它继承。 EBO 使用继承使空类(在某些情况下)使用零空间。由于您不能从 final 类继承,因此如果您是 final 类,它就不起作用。
  • 我认为template<class T> struct Finalized final : T {}; 是一个很好的解决方法。只需从 B 继承 EBO 和 typedef Finalized<B> 对于用户。
  • @templaterex 需要构造函数继承。
  • 是的,正确的,而且令人讨厌的是手动默认构造函数。所以也许不值得费心。
【解决方案2】:
  1. 不,它只在编译时使用

  2. Magic(see here 了解更多信息 - 感谢 Csq 提供链接)

【讨论】:

  • 您确定标记一个类final 不会强制为该类创建一个vtable,对于任何编译器?
猜你喜欢
  • 1970-01-01
  • 2017-09-28
  • 2017-03-26
  • 2019-04-06
  • 2013-03-28
  • 1970-01-01
  • 1970-01-01
  • 2010-09-15
  • 1970-01-01
相关资源
最近更新 更多