26

I am considering using virtual inheritance in a real-time application. Does using virtual inheritance have a performance impact similar to that of calling a virtual function? The objects in question would only be created at start up but I'm concerned if all functions from the hierarchy would be dispatched via a vtable or if only those from the virtual base class would be.

curiousguy
  • 7,344
  • 2
  • 37
  • 52
Graeme
  • 4,166
  • 2
  • 37
  • 64
  • 1
    Unless you are using multiple inheritance, there isn't really a need to use virtual inheritance. – Zac Howland Feb 04 '11 at 15:32
  • @ZacHowland, unless you are using mocking with Google Test. (gtest) – Prof. Falken Mar 09 '13 at 09:36
  • 3
    @Amigable: There is no "unless". When using Google Test, you still only use virtual inheritance when dealing with multiple inheritance. – Zac Howland Mar 12 '13 at 15:32
  • @ZacHowland, my mistake in that case. I thought it was a requisite to able to to mock classes. But I haven't actually started using it yet... so what do I know. – Prof. Falken Mar 12 '13 at 15:51
  • The Google Test framework allows you to create mock objects for non-pure-abstract classes, so when you inherit from these classes, you can run into a diamond situation (multiple inheritance) which would require virtual inheritance. It is still a better practice to use pure-abstract (aka "interfaces") and mock the interface with a new implementation, however. It will make your test code easier to write and maintain (in addition to making your actual code easier to write and maintain). – Zac Howland Mar 12 '13 at 17:50

3 Answers3

27

Common implementations will make access to data members of virtual base classes use an additional indirection.

As James points out in his comments, calling a member function of a base class in a multiple inheritance scenario will need adjustment of the this pointer, and if that base class is virtual, then the offset of the base class sub-object in the derived class's object depends on the dynamic type of the derived class and will need to be calculated at runtime.

Whether this has any visible performance impact on real-world applications depends on many things:

  • Do virtual bases have data members at all? Often, it's abstract base classes that need to be derived from virtually, and abstract bases that have any data members are often a code smell anyway.

  • Assuming you have virtual bases with data members, are those accessed in a critical path? If a user clicking on some button in a GUI results in a few dozen additional indirections, nobody will notice.

  • What would be the alternative if virtual bases are avoided? Not only might the design be inferior, it is also likely that the alternative design has a performance impact, too. It has to achieve the same goal, after all, and TANSTAAFL. Then you traded one performance loss for another plus an inferior design.


Additional note: Have a look at Stan Lippmann's Inside the C++ Object Model, which answers such questions quite thoroughly.

sbi
  • 204,536
  • 44
  • 236
  • 426
  • TO clarify, only calls to the virtual base classes members/functions result in additional indirection? – Graeme Feb 04 '11 at 15:32
  • @Graeme: I'm certainly no expert in this area, but I don't see how calls to virtual base class member _functions_ would result in a performance loss. They are either dispatched statically (`B::f()`) or dynamically through the derived class's virtual table, just like member functions of non-virtual bases. ICBWT. – sbi Feb 04 '11 at 15:35
  • 2
    @sbi: If the function is not virtual, then the function to be called can be selected statically, but the `this` pointer must be computed [or looked up] at runtime, right? – James McNellis Feb 04 '11 at 15:44
  • @James: Oh, that's right, I forgot `this` pointer adjustment. But that's due to _multiple_ inheritance, whether virtual or not, or is there some additional cost I'm forgetting about? – sbi Feb 04 '11 at 15:46
  • 1
    @sbi: I think it's the difference between a computation and a look up. In nonvirtual multiple inheritance, you can add a known offset to whatever pointer you have to obtain the `this` pointer. In virtual multiple inheritance, you have to go look up (at runtime) where the base class subobject is to get the `this` pointer. A lookup is "more expensive" than an addition, but how relevant that difference is depends on the application: as you say; unless this is a time-critical operation in a program with real-time performance constraints, it's not going to matter. – James McNellis Feb 04 '11 at 15:52
  • @sbi: neat acronym `TANSTAAFL` :p – Matthieu M. Feb 04 '11 at 15:58
  • @James: Ah, that's right! Then each call to a virtual function of the base class will result in such a lookup, right? – sbi Feb 04 '11 at 16:29
  • @Matthieu: I assumed that to be well known. Isn't it? (Maybe I've caught it reading Larry Niven or whoever used it in their books?) – sbi Feb 04 '11 at 16:30
  • @sbi: I knew the sentence behind it (first read it on Sutter's blog) but didn't mapped the acronym instantly... but Google did :) – Matthieu M. Feb 04 '11 at 16:31
  • @Matthieu: Yeah, [Wikipedia says](http://en.wikipedia.org/wiki/There_ain%27t_no_such_thing_as_a_free_lunch) it became popular through Heinlein's _the Moon is a Harsh Mistress_. That would fit my reading habits, too. `:)` – sbi Feb 04 '11 at 16:38
4

Take a look at the following large scale experimental study published OOPSLA'96. I am copy pasting a bibtex entry, the abstract and a link to the paper. I would consider this the most comprehensive experimental study on the topic to date.

@article{driesen1996direct,
  title={{The direct cost of virtual function calls in C++}},
  author={Driesen, K. and H{\\"o}lzle, U.},
  journal={ACM Sigplan Notices},
  volume={31},
  number={10},
  pages={306--323},
  issn={0362-1340},
  year={1996},
  publisher={ACM}
}

Abstract: We study the direct cost of virtual function calls in C++ programs, assuming the standard implementation using virtual function tables. We measure this overhead experimentally for a number of large benchmark programs, using a combination of executable inspection and processor simulation. Our results show that the C++ programs measured spend a median of 5.2% of their time and 3.7% of their instructions in dispatch code. For “all virtuals” versions of the programs, the median overhead rises to 13.7% (13% of the instructions). The “thunk” variant of the virtual function table implementation reduces the overhead by a median of 21% relative to the standard implementation. On future processors, these overheads are likely to increase moderately

http://www.cs.ucsb.edu/~urs/oocsb/papers/oopsla96.pdf

Nikhil
  • 2,050
  • 6
  • 31
  • 50
  • 5
    I wouldn't be surprised if compiler optimizations have rendered this study obsolete. It was published in 1996. – Brandon Kohn Aug 30 '14 at 12:02
  • 11
    Um. But the question was about ___virtual inheritance___, not about ___virtual functions___. – sbi Jun 30 '15 at 11:13
  • 4
    This study was done on processors from 1995. Only 32-bit processors were studied (having 256K cache (8K instruction cache)). Current desktop processors are 64-bit with 8MB cache. The Intel Pentium Pro studied did not have MMX. Might as well compare Windows 95 to Windows 10 (rhetorical comment; please don't). – David Thomas Jul 17 '16 at 02:44
0

Are you sure you mean virtual inheritance? If so, it's identical to the cost of a normal virtual function call. The vtable chained search just follows a specified path.

You said that this was at startup. Your disk overhead (from simply loading your code into memory) is likely to require orders of magnitude more time than the half-dozen instructions or so for vtable lookups. I'd be somewhat surprised if you could profile this and detect a difference.

jkerian
  • 14,951
  • 3
  • 42
  • 56