0

I have some classes (most of them are abstract, with virtual inheritance):

class A{
    public:
        virtual void f1() = 0;
        virtual void f2() = 0;
};

class B : virtual public A{
    public:
        virtual void f3() = 0;
};

class MyA : virtual public A{
    public:
        virtual void f1(){ ... }
        virtual void f2(){ ... }
};

class MyB : virtual public B, virtual public MyA{
    public:
        void f3(){ ... }
};

Now I use them:

B * object = new MyB();
object->f1(); //declared in A, imp. in MyA
object->f3(); //declared in B, imp. in MyB

Everything works fine, and the code is "good" for me (I can fast switch from MyB to YourB with changes in 1 line only).

But my question is:

How much additional memory it uses, compared to the similar code listed below (same result, different structure)?

I'm not good with memory layouts/vTables, so please explain it to me in a simple way - I want to know, if my application will spend more resources (memory) and if the executable will be slower?

And I compare that code to that one:

class MyA{
    public:
        virtual void f1(){ ... }
        virtual void f2(){ ... }
};

class MyB : public MyA{
    public:
        void f3(){ ... }
};

MyB * object = new MyB();
object->f1(); //declared in MyA, imp. in MyA
object->f3(); //declared in MyB, imp. in MyB

The sizeof(object) returns 4 in both examples (Win x32, Visual Studio native compiler), but I'm not sure if it's authoritative here. Maybe it doesn't count something - I don't think that both samples are 100% equal.

PolGraphic
  • 3,233
  • 11
  • 51
  • 108
  • Are you talking execution code size or memory/variable size? – Thomas Matthews May 12 '14 at 14:00
  • Both of them are important for me, but the most important is the total memory size occupied in system when I run the application. – PolGraphic May 12 '14 at 14:04
  • possible duplicate of [Where in memory is vtable stored?](http://stackoverflow.com/questions/1905237/where-in-memory-is-vtable-stored) – usr May 12 '14 at 14:05
  • 1
    This information is already given in surely many questions about vtables. This is a duplicate. Before asking a question, it is expected that you perform some research. – usr May 12 '14 at 14:06
  • The size of the *vtable* may differ. – Jarod42 May 12 '14 at 14:07
  • About the duplicate - I don't ask *where* the memory in vTable is stored (e.g. beginning of the object allocation) but how much memory will I spend. And the linked question did not give me the answer, maybe because my lack of knowledge/deduction (if so, sorry). – PolGraphic May 12 '14 at 14:10

3 Answers3

2

It depends on the implementation, but typically virtual inheritance will need:

  • an extra pointer (or offset) for each virtual base class: the adjustment to convert (for example) B* to A* will depend on which other subobjects in the same object also derive virtually from A. I think this can be stored in the vtable, rather than the object itself, so that the overhead could be per-class rather than per-object.
  • extra logic in the constructor and destructor, to determine whether or not the virtual base object needs initialising/destroying at that point.
  • extra work for some pointer conversions, reading the stored pointer/offset rather than applying a compile-time constant.

For memory usage, you can measure the per-object overhead in your implementation by printing sizeof (MyB). Any per-class overhead will probably be negligible, unless you have a huge number of classes.

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • 2
    If memory layout is interesting, gcc can do g++ -fdump-class-hierarchy – user877329 May 12 '14 at 14:05
  • Thank you! So it will be per-class costs more then per-instance costs. – PolGraphic May 12 '14 at 14:08
  • @PolGraphic: You should check that, if it matters to you. I'm just guessing what an implementation might do; there might be good reasons (e.g. performance) to put the adjustment in the object instead. – Mike Seymour May 12 '14 at 14:11
1

Before I start, your concern is known as a premature optimization. There are other concerns to worry about before size and space: correctness and robustness.

Inheritance is usually implement through Virtual Function Tables, in essence, a table of addresses to functions. So the amount of extra code space depends on the quantity of virtual functions.

Virtual functions are executed using a jump table. A common practice is to load the Program Counter with the value in the Function Table. This is usually 2 assembly instructions.

The amount of variable space for the function table may be less than the memory wasted by alignment padding in a structure. The wasted execution time is less than the overhead to call a function.

Edit 1:
BTW, assembly instructions are usually executed in 1 microsecond or less. So calling through a function table would take 2 microseconds. Compare this with waiting for disk I/O or User I/O.

This is why it is a premature optimization: optimizing before profiling. Profile the entire code and attend to the bottlenecks before worrying about this waste of code and variable space.

Thomas Matthews
  • 56,849
  • 17
  • 98
  • 154
  • Another nice answer (I can mark only one unfortunately, up-vote from me anyway). The comparison with I/O operations shows that it's "not a big deal". But my classes (MyB, MyA) can be the 3d engine classes (so they are called each frame, about 500 instances, 60 times per one second). – PolGraphic May 12 '14 at 14:14
1

For commonly used compilers, the overhead will be roughly as following

  1. Memory Overhead: extra pointer to vtable for each parent class.
  2. Runtime Overhead: each virtual method call will have indirections to find the right implementation of the method for actual type of the invoking object.

sizeof(object) returns 4 in both case because you are measuring size of pointer to object, not object itself. Pointer size is same no matter to which object it points.

Rakib
  • 7,435
  • 7
  • 29
  • 45
  • Right, thanks. The memory overhead will be the same for 10 and 1000 instances of objects? I mean - the overhead is per class, not per instance? – PolGraphic May 12 '14 at 14:11
  • 2
    AFAIK, yes, the memory overhead will be per-class. – Rakib May 12 '14 at 14:13