4

Is there any vtable/virtual cost for a virtual final function (final at base class)?

class B{
    public: virtual void fFinal() final{ .... do something  ..... }
    public: void fCheap() { .... do something ..... }
    public: virtual void fVirtual() { .... do something ..... }
};
class C : public B{
    public: virtual void fVirtual() { .... do something ..... }
};

Will the cost of fFinal() = cost of fCheap() or fVirtual()?

I am going to use final+virtual to prevent human-error ("Don't override me").
fCheap() is not so safe, because I can still hide the parent's function.

These below links don't provide answer.

Community
  • 1
  • 1
javaLover
  • 6,347
  • 2
  • 22
  • 67

2 Answers2

2

As far as I can tell, it is unspecified how virtual functions mechanism is implemented by any particular compiler. It is most likely that they put a pointer to vtable into the class if it has at least one virtual function even if this virtual function is marked as final.

I've tested a simplifed example based on your code snippet:

class Base {
    public:
        virtual void foo() final {}
};

static_assert(sizeof(Base) > 1, "No pointer to vtable");

Seems that both gcc 6.3 and clang 4.0 add a pointer to vtable.

It means that the rules which govern usual virtual functions apply for a function which marked both virtual and final in the base class. As a consequence, Base class grows in size and, and when you call foo via the pointer/reference to Base class or some class derived from Base, you pay some additional cost for being redirected through the vtable.

Edgar Rokjān
  • 17,245
  • 4
  • 40
  • 67
  • 1
    There is an evidence shows that vtable is generated --> imply that I will suffer cost of vtable? – javaLover Mar 19 '17 at 09:16
  • @javaLover Yes, I think so. – Edgar Rokjān Mar 19 '17 at 09:17
  • I am trying to generalize the idea. Assume `D` is a class with a single function (non-virtual) `f1()`. Later, I add virtual final function `f2()`. Will `f1()` also become slower from vtable indirection? – javaLover Mar 19 '17 at 09:21
  • 1
    @javaLover No, not really. Functions, which are not virtual, does not suffer from being invoked through the vtable. – Edgar Rokjān Mar 19 '17 at 09:23
  • Thank. That is insightful. I am still a little worry though. The cause that compiler generates vtable might be C++ specification or preference of compiler designer. However, compiler might optimize the code in a strange way, i.e. generate vtable but not access it. ..... If I have to pick, I believe you are correct, but I am not sure enough to sink all my function into it. It would be nice if you may also provide reference to support this. :) – javaLover Mar 19 '17 at 09:31
  • The C++ spec says nothing about vtables. – curiousguy Mar 21 '17 at 23:13
2

From a purely theoretical point of view without taking compiler optimiziation into account, fCheap() is indeed fastest. Both fFinal() and fVirtual() incur the cost of an added lookup/indirection because they have to be called through the vtable. Also object size will increase because of the vtable, but that has nothing to do with final. You pay the cost in size as soon as your class (or one of its bases) has any virtual functions at all.

Enter modern optimizers, i.e. devirtualization. The cost of increased object size won’t go away. The cost of the virtual calls might. Declaring a virtual function and immediately making it final makes it relatively easy for the compiler to proof at compile time exactly which function will be called. Bets are the fFinal() call will be devirtualized to a normal function call[1]. If that can happen for FVirtual() as well entirely depends on the situation at the call site.

In general virtual call overhead is small. I wouldn’t worry about it too much unless you have conrete evidence from profiling your actual code that this is a performance bottleneck.

Update

[1] How likely you are to win the bet depends on your compiler, its version and configuration. The only way to make sure is to look at the assembly generated from your actual code. I wouldn’t dare to make a general statement here. I played around a bit with recent GCC and Clang at -O3 in the Compiler Explorer. In every example I tried fFinal() was inlined (granted, they were kind of trivial). So, obviously, both compilers had no problem proofing away even more than virtuality. :)

besc
  • 2,507
  • 13
  • 10
  • I am also going to use it for get/set and all things. It is for games, so I have to optimize as much as I can (to reach maximum fps). Thank for mention about size of vtable. If you may happen to know the certain **bet** result, please ping me. – javaLover Mar 19 '17 at 09:39
  • Judging that bet is highly non-trivial … updated the answer with a bit more info. – besc Mar 19 '17 at 15:22