Performance of virtual functions when called by derived classes?

Is there a performance limitation when a virtual method is called from a class that is known to be a derived class at compile time? Below I directly call force_speak derived class.

code:

 #include <iostream> #include <array> #include <memory> class Base { public: virtual void speak() { std::cout << "base" << std::endl; } }; class Derived1 : public Base { public: void speak() { std::cout << "derived 1" << std::endl; } }; template<class B> void force_speak(std::array<std::unique_ptr<B>, 3>& arr) { for (auto& b: arr) { b->speak(); } } int main() { std::array<std::unique_ptr<Derived1>, 3> arr = { std::unique_ptr<Derived1>(new Derived1), std::unique_ptr<Derived1>(new Derived1), std::unique_ptr<Derived1>(new Derived1) }; force_speak(arr); return 0; } 
+6
source share
3 answers

Is there a performance limitation when a virtual method is called from a class that is known to be a derived class at compile time? See code below.

It depends. Most compilers will de-virtualize the code as follows:

 Derived1 d; d.speak(); 

The dynamic type of an object is known at the call site, so the compiler can avoid passing through the vtable to call and can simply call Derived1::speak() directly.

In your example, the compiler should be smarter, because in force_speak you only have Derived1* pointers (stored inside unique_ptr objects), and in this context it does not unique_ptr out if the dynamic type of objects with a pointer is Derived1 or some more derived type. The compiler needs to include a force_speak call in main (where the dynamic type is known) or use some additional type information to enable devirtualization. (As an example of additional knowledge, optimizing the entire program may determine that there are no other derived types in the production program, so Derived1* must point to Derived1 .)

Using the C ++ 11 final keyword can help compilers devirtualize some cases, for example. if Derived1 marked final , then the compiler knows that Derived1* can only point to Derived1 , and not to any other type derived from it that can override speak()

+6
source
  • It depends on the compiler. The compiler should statically know that Derived1:speak() is the only option. This means that there is no definition of Derived2::speak() , where class Derived2: public Derived1 . But the compiler cannot implement such optimization at all.

  • Function template parameters can be automatically output by the compiler. This is part of the C ++ standard. The compiler knows the type of parameter on the call site, so the user should not provide it. Note that the user can provide a type, and thay can, for example, provide type compatibility, but is different from the type of the actual parameter.

+2
source

In this particular case, the answer may be.

If the compiler decides to embed force_speak() , we can theoretically conclude that all pointers in the array are instances of Derived1 and therefore invoke the method statically. (This standard optimization is not required, so the method is called statically or actually depends on your specific compiler and, possibly, what parameters you use at compile time.)

If the compiler does not embed the call, it should give instructions for calling the method practically, because you could get the Derived1 class even more and override the method again, save the instances of this class in std::unique_ptr<Derived1> and pass the array from them to the function .

+1
source

Source: https://habr.com/ru/post/979809/


All Articles