当我从虚拟基础派生D时,为什么在VS2015中sizeof(D)增加了8个字节?

Ayr*_*osa 6 c++ alignment virtual-inheritance c++14

我正在使用C++14§3.11/ 2中的示例:

struct B { long double d; };
struct D : virtual B { char c; }
Run Code Online (Sandbox Code Playgroud)

在clang,g ++和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';
}
Run Code Online (Sandbox Code Playgroud)

我得到了以下结果:

                         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
Run Code Online (Sandbox Code Playgroud)

现在,在取消上面代码virtual中的定义struct D并再次为clang,g ++和VS2015运行代码之后,我获得了以下结果:

                         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
Run Code Online (Sandbox Code Playgroud)

我对上面得到的结果毫不怀疑,只有一个例外:为什么sizeof(D)在VS2015中从16增加到24?

我知道这是实现定义的,但是对于这种大小的增加可能有一个合理的解释.如果可能的话,这就是我想知道的.

JSF*_*JSF 1

如果您实际上利用了虚拟继承的虚拟方面,我认为对 vtable 指针的需求就会变得清晰。vtable 中的一项可能是 的开头与 的开头之间的偏移BD

假设E实际上从两者继承,B并且F从两者继承,因此内部 an最终使用内部作为其基类。在一种不知道它是基类的方法中,如果没有存储在 vtable 中的信息,如何找到成员?EDDFBEDFB

所以 clang 和 G++ 将 8 个字节的填充更改为 vtable 指针,而您认为没有变化。但VS2015从来没有这样的填充,所以需要为vtable指针添加8个字节。

也许编译器注意到 vtable 指针的唯一用途是在计算基指针的低效方案中。因此,也许可以将其优化为简单地使用基指针而不是虚函数表指针。但这不会改变对 8 字节的需求。