Dan*_*l H 7 c++ inheritance class sizeof
更具体地说,一个继承自空类的类,只包含一个union,其成员包含一个基本无数据类的实例,占用的内存比union更多.为什么会发生这种情况,有没有办法避免花费额外的内存?
以下代码说明了我的问题:
#include <iostream>
class empty_class { };
struct big : public empty_class
{
union
{
int data[3];
empty_class a;
};
};
struct small
{
union
{
int data[3];
empty_class a;
};
};
int main()
{
std::cout << sizeof(empty_class) << std::endl;
std::cout << sizeof(big) << std::endl;
std::cout << sizeof(small) << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
使用gcc版本7.3.0编译时,此代码的输出-std=c++17
(尽管我使用c ++ 11和c ++ 14得到相同的结果)是:
1
16
12
Run Code Online (Sandbox Code Playgroud)
我期望类的大和小的应该是相同的大小; 然而奇怪的是,即使它们两者看起来都包含相同的数据,大的内存也比小的内存多.
也即使在工会阵列的大小被改变,大小之间的差大和小是常数4个字节.
-编辑:
看起来这种行为并不特定于具有联合数据类型的类.类似的行为发生在派生类具有基类类型的成员的其他类似情况中.感谢那些指出这一点的人.
Nic*_*las 12
这是因为我称之为C++的"唯一身份规则".C++中特定类型的每个(实时)对象T
必须始终具有与每个其他类型的活动对象不同的地址T
.编译器无法为违反此规则的类型提供布局,其中具有相同类型的两个不同子对象T
在其包含对象的布局中具有相同的偏移量.
类big
包含两个注意的子对象:基类empty_class
和包含成员的匿名联合empty_class
.
空基本优化基于对具有其他类型的空基类的"存储"进行别名.通常,这是通过为其提供与父类相同的地址来完成的,这意味着该地址通常与第一个非空基或第一个成员子对象相同.
如果编译器为基类提供empty_class
了与union成员相同的地址,那么您将拥有类(big::empty_class
和big::a
)的两个不同的子对象,它们具有相同的地址但是是不同的对象.
这样的布局会违反唯一身份规则.因此,编译器不能在此使用空基优化.这也是为什么big
不是标准布局.
Bat*_*eba 10
这union
是一个红鲱鱼.
如果你简化到
struct empty{};
struct big : empty
{
empty e;
};
Run Code Online (Sandbox Code Playgroud)
然后sizeof(big)
必须大于sizeof(empty)
.这是因为有两类对象empty
中big
,因此它们需要不同的地址.该空基地优化在这里不能应用,因为它可能是
struct small : empty
{
int n;
};
Run Code Online (Sandbox Code Playgroud)
在那里你可以期望sizeof(small)
是sizeof(int)
.