简体   繁体   English

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

[英]Can a compiler inline a virtual function if I use a pointer in a clear situation?

I've already read Are inline virtual functions really a non-sense? 我已经阅读过内联虚拟功能真的没有意义吗? . But I still have some doubts and found no answer there. 但我仍有一些疑虑,并没有找到答案。

They say that if situation isn't ambiguous, compiler should inline the virtual function . 他们说如果情况不明确,编译器应该内联虚函数

However: 然而:

This can happen only when the compiler has an actual object rather than a pointer or reference to an object. 只有当编译器具有实际对象而不是指针或对象的引用时,才会发生这种情况。

So what if I have a B class derived from an A one (which contains a virtual void doSth() function) and I use the B* pointer, not the A* : 那么如果我有一个来自AB类(它包含一个virtual void doSth()函数)并且我使用B*指针而不是A*

B* b = new B;

b->doSth();
  1. Suppose that the B hasn't any child classes. 假设B没有任何子类。 It's rather obvious (on the compile time) what function should be called. 在编译时应该调用什么函数是相当明显的。 So it's possible to be inlined. 所以可以内联。 Is it in fact? 实际上是吗?
  2. Suppose that the B has some child classes but these classes haven't its own doSth() function. 假设B有一些子类,但这些类没有自己的doSth()函数。 So compiler should "know" that the only function to call is B::doSth() . 所以编译器应该“知道”唯一要调用的函数是B::doSth() I guess it doesn't inline though? 我猜它虽然没有内联?

It doesn't matter whether B has any derived classes. B是否有任何派生类并不重要。 In that situation b points to a B object so the compiler can inline the call. 在那种情况下, b指向B对象,因此编译器可以内联调用。

And surely any decent modern compiler can and will do that in your situation. 当然,任何体面的现代编译器都可以并且将会在您的情况下执行此操作。 If you don't use pointers it becomes a whole lot easier. 如果你不使用指针,那就变得容易多了。 It's not really an "optimization" then. 那不是真正的“优化”。 The fact that you can omit a virtual call then becomes obvious by only looking at the AST node at the left side of the . 通过只查看左侧的AST节点,您可以省略虚拟调用的事实变得明显. -operator. - 运算符。 But if you use pointers, you need to track the dynamic type of the pointee. 但是如果使用指针,则需要跟踪指针的动态类型。 But modern compilers are capable of that. 但现代编译器能够做到这一点。

EDIT: Some experiment is in order. 编辑:一些实验是有序的。

// 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
}
// ...

As can be seen, clang does direct calls to f , both when a points to a A and when it points to a B . 可以看出,clang确实直接调用f ,无论a指向A还是指向B GCC does that too. 海湾合作委员会也这样做。

A virtual member function can be inlined when the vtable is not dereferenced for the call. 当vtable未被解除引用以进行调用时,可以内联虚拟成员函数。 This can be accomplished by making an explicitly scoped call to the member function. 这可以通过对成员函数进行显式范围调用来完成。

class A
{
protected:

    int     a;
public:
    inline virtual void Func()
    {
        a = 0;
    }
};

class B : public A
{
public:
    inline virtual void Func()
    {
        a = 1;
    }
};

B   *obj = new B();

obj->Func();    //  Calls B::Func() through vtable;
obj->A::Func(); //  Inlines calls to A::Func();
obj->B::Func(); //  Inlines calls to B::Func();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM