Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why C++ virtual call is not much slower than a non-virtual one?

In my undetrstanding, for a C++ virtual call, it needs to:

  1. Get the type of the object from the symbol table
  2. Get the v-table from the type table
  3. Search the function using the function signature in the v-table
  4. Call the function.

While for a non-virtual (such as in C) call, only #4 is required.

I think that #3 should be the most time consuming. Given the nature of realtime overriding in C++, I could not see much potential for compilation time optimization for the above steps. Thus for a complex class inheritance with long function signatures, a C++ virtual call should be much slower than a non-virtual call.

But all claims are contrary, why?

like image 418
CPW Avatar asked Dec 05 '12 04:12

CPW


People also ask

Why is a virtual function call slower?

Virtual functions are slow when you have a cache miss looking them up. As we'll see through benchmarks, they can be very slow. They can also be very fast when used carefully — to the point where it's impossible to measure the overhead.

Are virtual methods slower?

Virtual functions are by definition slower than their non-virtual counterparts; we wanted to measure the performance gains from inlining; using virtual functions would make the difference even more pronounced.

What happens when we call virtual function in non-virtual function?

So polymorphic behaviour works even when a virtual function is called inside a non-virtual function. The output can be guessed from the fact that the function to be called is decided at run-time using the vptr and vtable.

Is virtual function call is resolved at runtime?

Virtual functions ensure that the correct function is called for an object, regardless of the type of reference (or pointer) used for function call. Functions are declared with a virtual keyword in base class. The resolving of function call is done at runtime.


1 Answers

  1. Get the type of the object from the symbol table
  2. Get the v-table from the type table
  3. Search the function using the function signature in the v-table
  4. Call the function.

This is a poor understanding of how v-table-based dispatch works. It's much simpler:

  1. Get the v-table from the object pointer. Pick the right v-table for the function in question (if multiple base classes are used).
  2. Add a specific offset, compile-time determined, to this v-table pointer, thus fetching a specific function pointer.
  3. Call that function pointer.

Each object has a v-table pointer, which points at the v-table for that object's original type. So there's no need to fetch the type from a "symbol table". No searching of the v-table is necessary. It's compile-time determinable exactly which pointer in the v-table needs to be accessed, based on the function signature provided at compile time. It's all about how the compiler indexes each virtual function in a class. It can determine a specific order for each virtual function, and thus when the compiler goes to call it, it can determine which function to call.

So it's quite fast overall.

It's a bit more complex when dealing with virtual base classes, but the general idea is still the same.

like image 95
Nicol Bolas Avatar answered Sep 28 '22 14:09

Nicol Bolas