Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why the sizeof(D) increased by 8 bytes in VS2015 when I derived D from a virtual base?

I'm using the example in C++14 §3.11/2:

struct B { long double d; };
struct D : virtual B { char c; }

After running the snippet below in clang, g++ and VS2015

#include <iostream>
struct B { long double d; };
struct D : /*virtual*/ B { char c; };

int main()
{
    std::cout << "sizeof(long double) = " << sizeof(long double) << '\n';
    std::cout << "alignof(long double) = " << alignof(long double) << '\n';

    std::cout << "sizeof(B) = " << sizeof(B) << '\n';
    std::cout << "alignof(B) = " << alignof(B) << '\n';

    std::cout << "sizeof(D) = " << sizeof(D) << '\n';
    std::cout << "alignof(D) = " << alignof(D) << '\n';
}

I got the following results:

                         clang           g++         VS2015  
sizeof(long double)        16             16            8
alignof(long double)       16             16            8
sizeof(B)                  16             16            8
alignof(B)                 16             16            8
sizeof(D)                  32             32           16
alignof(D)                 16             16            8

Now, after uncommenting the virtual in the definition of struct D in the code above and running the code again for clang, g++ and VS2015, I obtained the following results:

                         clang           g++         VS2015  
sizeof(long double)        16             16            8
alignof(long double)       16             16            8
sizeof(B)                  16             16            8
alignof(B)                 16             16            8
sizeof(D)                  32             32           24
alignof(D)                 16             16            8

I have no doubts about the results obtained above, with one single exception: why did the sizeof(D) increased from 16 to 24 in VS2015?

I know this is implementation defined, but there might be a reasonable explanation for this increase in size. This is what I'd like to know if possible.

like image 677
Ayrosa Avatar asked Dec 09 '15 12:12

Ayrosa


1 Answers

If you actually make use of the virtual aspect of virtual inheritance, I think the need for the vtable pointer becomes clear. One item in the vtable is likely the offset of the start of B from the start of D.

Assume E inherits virtually from B and F inherits from both E and D such that the D inside an F ends up using the B inside the E for its base class. In a method of D that doesn't know it is a base class of F how could you find members of B without info stored in the vtable?

So clang and G++ changed 8 bytes of padding into a vtable pointer and you thought there was no change. But VS2015 never had that padding, so it needed to add 8 bytes for vtable pointer.

Maybe a compiler notices that the only use of the vtable pointer is in an inefficient scheme for computing the base pointer. So maybe that is optimized into simply having a base pointer instead of a vtable pointer. But that would not change the need for the 8 bytes.

like image 99
JSF Avatar answered Oct 17 '22 12:10

JSF