【问题标题】:Does the final keyword provide optimization if all derived classes are known at compile time?如果在编译时知道所有派生类,final 关键字是否提供优化?
【发布时间】:2019-10-26 02:58:03
【问题描述】:

理论上,在 C++11 及更高版本中的虚拟方法声明上使用 final 关键字可以内联方法。

This can be seen here.

但是,我怀疑在实践中,如果在编译时知道没有派生类覆盖该方法,编译器可以为我们插入一个final 并内联该方法。

However, putting this into compiler explorer shows that it still provides optimizations.

这是为什么?

【问题讨论】:

  • “如果在编译时知道没有派生类”。你怎么知道的?
  • 我可以阅读代码并看到没有任何派生类。
  • 所以只能在link做,假设没有动态加载...
  • 啊,这就是我缺少的一点。因此,如果我使用链接时优化,编译器可能会自动将方法标记为final。如果您可以将仅知道在链接时可用的派生类型添加到您的答案中,我会接受它。

标签: c++ performance optimization compilation final


【解决方案1】:

C++11 及以后的虚拟方法声明中的 final 关键字允许内联方法

不是inlining,而是去虚拟化。

但是,我怀疑在实践中,如果在编译时知道没有派生类覆盖该方法,[..]

您无法在编译时知道没有其他派生类(除非类是final):用户或其他 TU 可能会提供一些。假设没有动态加载,它可能会在链接处完成......

[..] 编译器可以为我们插入一个 final 并内联该方法 但是,将其放入编译器资源管理器表明它仍然提供优化。

 struct A {
     virtual void f() {}
 };

struct B : public A {
     void f() final override {}
 };

struct C : public A {
     void f() override {}
 };
void foo(B& b) { b.f(); }
void bar(C& c) { c.f(); }
C::f():
        rep ret
foo(B&):
        rep ret
bar(C&):
        mov     rax, QWORD PTR [rdi]
        mov     rax, QWORD PTR [rax]
        cmp     rax, OFFSET FLAT:C::f()
        jne     .L6
        rep ret
.L6:
        jmp     rax

这是为什么?

这里,当c 的动态类型为C 时,编译器内联调用C::f (rep ret): 然后不是调用C::f,而是执行C::f 所做的事情(-> 什么都不做)。

虚拟调用还是调用其他动态类型(jmp rax)。

【讨论】:

    【解决方案2】:

    优化方面,final 仅影响编译器是否可以在编译时证明派生类型是什么。如果类型已知,则无需帮助编译器知道它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-22
      • 2012-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多