What is the price of virtual inheritance?

This seems to be a fundamental question, but I have not seen him ask:

Suppose the following simple case:

  • There are no virtual members.

  • Virtual inheritance is used to resolve multiple paths to the same base.

What is the price of virtual inheritance in terms of the time required to access members of the derived class itself? In particular, if there is a non-zero price, does it apply only to members that are inherited in more than one way or to other members?

+5
source share
2 answers

What is the price of virtual inheritance in terms of the time required to access members of the derived class itself?

one shift-search and addition (2 commands and memory fetch)

In particular, if there is a non-zero price, does it apply only to members that are inherited in more than one way or to other members?

Yes, and even then not always. If the compiler has enough information to prove that access does not have to be indirect, it can shorten the search at compile time.

Perhaps it would be good to clarify when this will be so. - Nicol Bolas

Well said sir.

Here is an example to demonstrate this. Compile with the -O2 and -S options to see the optimization in action.

#include <memory> #include <string> enum class proof { base, derived }; // volatile forces the compiler to actually perform reads and writes to _proof // Without this, if the compiler can prove that there is no side-effect of not performing the write, // it can eliminate whole chunks of our test program! volatile proof _proof; struct base { virtual void foo() const { _proof = proof::base; } virtual ~base() = default; }; struct derived : base { void foo() const override { _proof = proof::derived; } }; // factory function std::unique_ptr<base> make_base(const std::string&name) { static const std::string _derived = "derived"; // only create a derived if the specified string contains // "derived" - on my compiler this is enough to defeat the // optimiser if (name == _derived) { return std::make_unique<derived>(); } else { return {}; } } auto main() -> int { // here the compiler is fully aware that p is pointing at a derived auto p = std::make_unique<derived>(); // therefore the call to foo() is made directly (in fact, clang even inlines it) p->foo(); // even here, the compiler 'knows' that b is pointing at a 'derived' // so the call to foo is made directly (and indeed on my compiler, completely // inlined) auto b = std::unique_ptr<base>(new derived); b->foo(); // here we assign a derived to b via indirect construction through a string. // Unless the compiler is going to track this string and follow the logic in make_base // (and on my compiler it does not) this will prevent the virtual call to foo() from // being turned into a direct call. // Therefore, this call will be made via the virtual function table of *b b = make_base("derived"); if (b) { b->foo(); } return 0; } 
+5
source

Access to data elements of the virtual base class is carried out using additional indirectness.

+3
source

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


All Articles