如果我像这样定义一个类:
class A{
public:
A(){}
virtual ~A(){}
virtual void func(){}
};
这是否意味着虚析构函数和func
都被内联了?
class A{
public:
A(){}
virtual ~A(){}
virtual void func(){}
};
这是否意味着虚析构函数和func
都被内联了?
virtual
函数。例如,当您使用类型A
的值时,编译器知道动态类型不可能不同,并且可以内联该函数。当使用指针或引用时,编译器通常无法证明静态类型相同,因此virtual
函数通常需要遵循常规的虚拟调度。然而,即使使用指针,编译器可能从上下文中获得足够的信息来知道确切的动态类型。例如,MatthieuM.给出了以下示例:A* a = new B;
a->func();
a->A::func()
)是另一个通常可进行内联的明显示例。 - user743382Base* b = new Derived{}; b->func();
,如果编译器足够聪明地意识到 b
的动态类型必然是 Derived
,则该调用可以被内联化。Clang 就是这样一个聪明的编译器。 - Matthieu M.struct Base { virtual void foo() = 0; };
struct Derived: Base { virtual void foo() { std::cout << "Hello, World!\n"; };
void opaque(Base& b);
void print(Base& b) { b.foo(); }
int main() {
Derived d;
opaque(d);
print(d);
}
Derived::foo
,但Clang/LLVM不会进行优化。问题在于:
print(d)
替换为d.foo()
并去虚拟化该调用。print(d)
替换为d.foo()
,它仍然假定d
的虚拟指针可能已被opaque
更改(其定义是不透明的,正如名称所示)。我一直关注Clang和LLVM邮件列表上的努力,因为两组开发人员都在思考信息的丢失以及如何让Clang告诉LLVM:“没问题”,但不幸的是这个问题并不简单,目前还没有解决...因此在前端进行了半吊子去虚拟化以尝试解决所有明显的情况,以及一些不太明显的情况(尽管按照惯例,前端不是实现它们的地方)。
供参考,Clang中去虚拟化的代码可以在CGExprCXX.cpp中找到一个名为canDevirtualizeMemberFunctionCalls
的函数。它只有大约64行(目前)并且有详细的注释。