如果我在明确的情况下使用指针,编译器可以内联虚函数吗?

som*_*ock 10 c++ compiler-construction virtual inline

我已经阅读过内联虚拟功能真的没有意义吗?.但我仍有一些疑虑,并没有找到答案.

他们说如果情况不明确,编译器应该内联虚函数.

然而:

只有当编译器具有实际对象而不是指针或对象的引用时,才会发生这种情况.

那么,如果我有一个B派生自一个类的类A(包含一个virtual void doSth()函数)并使用B*指针,而不是A*:

B* b = new B;

b->doSth();
Run Code Online (Sandbox Code Playgroud)
  1. 假设B没有任何子类.在编译时应该调用什么函数是相当明显的.所以可以内联.实际上是吗?
  2. 假设B有一些子类,但这些类没有自己的doSth()功能.所以编译器应该"知道"唯一要调用的函数B::doSth().我猜它虽然没有内联?

Joh*_*itb 14

是否B有任何派生类并不重要.在那种情况下b指向一个B对象,因此编译器可以内联调用.

当然,任何体面的现代编译器都可以并且将会在您的情况下执行此操作.如果你不使用指针,那就变得容易多了.那不是真正的"优化".通过查看.-operator 左侧的AST节点,您可以省略虚拟调用的事实变得明显.但是如果使用指针,则需要跟踪指针的动态类型.但现代编译器能够做到这一点.

编辑:一些实验是有序的.

// main1.cpp
struct A {
  virtual void f();
};

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

void g() {
  A *a = new A;
  a->f();

  a = new B;
  a->f();
}

// clang -O2 -S -emit-llvm -o - main1.cpp | c++filt
// ...
define void @g()() {
  %1 = tail call noalias i8* @operator new(unsigned int)(i32 4)
  %2 = bitcast i8* %1 to %struct.A*
  %3 = bitcast i8* %1 to i32 (...)***
  store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @vtable for A, i32 0, i32 2) to i32 (...)**), i32 (...)*** %3, align 4
  tail call void @A::f()(%struct.A* %2)
  %4 = tail call noalias i8* @operator new(unsigned int)(i32 4)
  %5 = bitcast i8* %4 to i32 (...)***
  store i32 (...)** bitcast (i8** getelementptr inbounds ([3 x i8*]* @vtable for B, i32 0, i32 2) to i32 (...)**), i32 (...)*** %5, align 4
  %tmp = bitcast i8* %4 to %struct.B*
  tail call void @B::f()(%struct.B* %tmp)
  ret void
}
// ...
Run Code Online (Sandbox Code Playgroud)

可以看出,fa指向a A和指向a 时,clang会直接调用B.海湾合作委员会也这样做.

  • @Johannes,谢谢你去找麻烦.看起来我不得不低估现代编译器的功能; 这不是我第一次感到惊讶. (2认同)