【发布时间】:2015-08-12 14:12:22
【问题描述】:
在class 或function 上使用说明符final 会增加任何内存或cpu 开销,还是仅在编译时使用?
std::is_final 如何识别什么是最终的?
【问题讨论】:
-
第二部分的答案在这里:stackoverflow.com/questions/13809359/…
在class 或function 上使用说明符final 会增加任何内存或cpu 开销,还是仅在编译时使用?
std::is_final 如何识别什么是最终的?
【问题讨论】:
它实际上可以减少开销。在极少数情况下,增加它。
如果您有一个指向final 类A 的指针,则可以对任何虚拟方法调用进行去虚拟化并直接调用。类似地,对虚拟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 发现)
【讨论】:
template<class T> struct Finalized final : T {}; 是一个很好的解决方法。只需从 B 继承 EBO 和 typedef Finalized<B> 对于用户。
不,它只在编译时使用
Magic(see here 了解更多信息 - 感谢 Csq 提供链接)
【讨论】:
final 不会强制为该类创建一个vtable,对于任何编译器?