2

I wanted to know the ordering of member variables and vtable pointers in C++ on a diamond virtual inheritance.

Consider the below inheritance:

class Base
{
    int b;
};

class Derived: public virtual Base
{
    int d;
};

class Derived2: public virtual Base
{
    int d2;
};

class Derived3: public Derived, public Derived2
{
    int d3;
};

I wanted to know the memory layout of class Derived3. I looked at following links online:

c++ data alignment /member order & inheritance

C++ Inheritance Memory Model

After going through the above links this is what I feel the memory layout of Derived3 could be:

void* vtable_ptr1 //vtable pointer of Derived
int d //Derived
void* vtable_ptr2 //vtable pointer of Derived2
int d2 //Derived2
int b //Base? not sure where will this be.
int d3 //Derived3

Online compilers give the size of Derived3 as 40 bytes, so I feel (assuming 8 bytes for pointer and 4 bytes for int) int b has to come after vtable_ptr2 (8(vtable_ptr1) + 4(d) + [4 padding] + 8(vtable_ptr2) + 4(d2) + 4(b) + 4(d3) + [4 class padding]) or before vtable_ptr1 (4(b) + [4 padding] + 8(vtable_ptr1) + 4(d) + [4 padding] + 8(vtable_ptr2) + 4(d2) + 4(d3)) so that padding comes into picture and increases the size of the class to 40.

To summarize, I have the following question:

Is the ordering correct? If not, what is the correct ordering of member variables and vtable pointers?

Naveen Kedilaya
  • 118
  • 1
  • 7
  • 4
    The C++ standard doesn't mandate anything for this (doesn't even mandate the use of vtables if I remember correctly). So there is no "correct order". – Mat Jan 07 '22 at 11:41
  • Why diamond inheritance in the first place? I usually try to avoid using it in my designs, I almost always run into maintenance/refactoring issues if I run into them. If you want it for code reuse there are other patterns like aggregation or crtp/mixin. Also read this : https://stackoverflow.com/questions/406081/why-should-i-avoid-multiple-inheritance-in-c – Pepijn Kramer Jan 07 '22 at 11:45
  • 1
    @Mat So the size of the class will depend on the compiler's implementation in this case? – Naveen Kedilaya Jan 07 '22 at 11:47
  • 1
    Could you try it out and print the member offsets with https://en.cppreference.com/w/cpp/types/offsetof e.g. on godbolt.org / msvc.godbolt.org with clang, gcc and msvc. And tell us the results, so we can discuss them? Here are some more powerful/compatible versions of offsetof: https://stackoverflow.com/questions/1129894/why-cant-you-use-offsetof-on-non-pod-structures-in-c – Sebastian Jan 07 '22 at 14:27
  • 1
    I heard that "Inside the C++ Object Model" by Stanley B. Lippman is a good book on the subject. Perhaps you can find a copy. – Sebastian Jan 07 '22 at 14:33
  • @Sebastian Offset of d=8, d2=24, d3=28. On trying to print offset of b, I get the error "error: invalid access to non-static data member ‘Base::b’ in virtual base of NULL object". But its obvious that "b" will come at the end. So the order (according to the compiler at [OnlineGDB](https://www.onlinegdb.com/online_c++_compiler) ) would be [vtable_ptr1, d, vtable_ptr2, d2, d3, b]. – Naveen Kedilaya Jan 10 '22 at 05:00

1 Answers1

4

what is the correct ordering of member variables and vtable pointers?

There is no "correct ordering". This is not specified in the C++ standard. Each compiler is free to arrange the memory layout of this class hierarchy in any fashion that's compliant with the C++ standard.

A compiler may choose the layout of the class, in this situation, according to some fixed set of rules. Or, a compiler may try to optimize amongst several possibilities and pick a layout that can take advantage of hardware-related factors, like preferred alignment of objects, to try to minimize any required padding. This is entirely up to the compiler.

Furthermore: if you review the text of the C++ standard you will not find even a single mention of anything called a "vtable". It's not there. This is just the most common implementation mechanism for virtual class methods and virtual inheritance. Instead of a pointer, it would be perfectly compliant with the C++ standard for a C++ compiler to use a two-byte index into a table, instead of an entire pointer -- into a table containing records that define each particular class's virtual properties. This would work perfectly fine as long as the number of all classes with virtual properties does not exceed 65536.

In other words: you have no guarantees, whatsoever, what this class's layout will be, in memory, or what its size is. It is not specified in the C++ standard and is entirely implementation-defined.

Sam Varshavchik
  • 114,536
  • 5
  • 94
  • 148