1、C语言中的空结构体
曾对C语言中的空结构体进行了简单分析(直达)
2、空类对象的大小
下面输出什么?
#include <iostream>
using namespace std;
class Base
{
};
int main()
{
cout << sizeof(Base) << endl;
return 0;
}
VS2015
g++(7.3.0 or 4.4.0)
g++(4.45)
BCC55(标准C++)
下面看看对于这种现象的解释
The size of any object or member subobject (unless [[no_unique_address]] -- see below) (since C++20) is required to be at least 1 even if the type is an empty class type (that is, a class or struct that has no non-static data members), in order to be able to guarantee that the addresses of distinct objects of the same type are always distinct.
However, base class subobjects are not so constrained, and can be completely optimized out from the object layout:
- https://cppreference.com
蓝色画线部分清晰地说明了:
任何对象或成员子对象的大小要求至少为1,即便该类型是空类类型
以便能够保证相同类型的不同对象的地址始终是不同的。
橙色部分指出特殊情况:
基类子对象不是那么受约束,可以从对象布局中完全优化
- 空白基类优化
3、实验分析
空白基类优化 empty.cpp
#include <iostream>
#include <cassert>
using namespace std;
class Base {}; // empty class
class Derived : Base
{
int i;
};
int main()
{
// the size of any object of empty class type is at least 1
assert(sizeof(Base) >= 1);
cout << sizeof(Base) << endl;
cout << sizeof(Derived) << endl;
// empty base optimization applies
assert(sizeof(Derived) == sizeof(int));
return 0;
}
在VS2015,g++ 7.3.0 or g++ 4.4.0 or g++ 4.4.5
编译运行成功即断言正确:空基类对象大小至少为1,空白基类会优化
在Borland C++ 5.5.1 (标准C++)
22行断言失败,即:空基类对象大小至少为1,没有进行空白基类会优化
至于为什么派生类得到16 : 成员i偏移地址为12 + 大小为4 = 16 内存对齐(直达)
实验结论:
★ 任何对象或成员子对象的大小要求至少为1,即便该类型是空类类型
★ 空白类作基类时可能进行优化 - 空白基类优化
★ 空白类的大小是未定义的,以及空白类作基类是否优化也是未定义的
★ 现代编译器大多将空白类大小置为1,并进行空白基类优化
4、进一步分析
什么时候空白类作基类不进行优化?
1、已经实验得知:如一些古老编译器BCC55不会进行空白基类优化
2、基类在派生类中产生了实例(基类不被static修饰)
3、多重继承中作基类(可能)
4、使用属性关键字 [[no_unique_address]](C++20)
5、编程实验
空白类作基类不进行优化 empty.cpp
基类在派生类中产生实例
#include <cassert>
#include <iostream>
using namespace std;
class Base
{
// empty class
};
class Derived1 : Base
{
int i;
};
class Derived2 : Base
{
Base c; //若在此处用static修饰,结果为1,4,8,12
int i;
};
class Derived3 : Base
{
Derived1 c;
int i;
};
int main()
{
cout << sizeof(Base) << endl;
cout << sizeof(Derived1) << endl; //优化
cout << sizeof(Derived2) << endl; //未优化
cout << sizeof(Derived3) << endl; //优化
assert(sizeof(Derived2) == 2 * sizeof(int));
assert(sizeof(Derived3) == 2 * sizeof(int));
return 0;
}
VS2015
多重继承作基类
VS2015
没有优化
g++ 4.4.0
优化
扩展[[no_unique_address]]
(C++20)
#include <cassert>
#include <iostream>
using namespace std;
class A {}; // empty class
class B
{
int i;
[[no_unique_address]] A a;
};
int main()
{
assert(sizeof(A) >= 1);
cout << sizeof(A) << endl;
cout << sizeof(B) << endl;
assert(sizeof(B) == sizeof(int)); //必须支持此属性关键字才可以可能被优化
return 0;
}
6、面试中的空类
如果考虑更多,对于“空类”类中含有
1、静态成员变量(放置静态存储区),成员函数
2、虚函数(类中加上指向虚函数表的指针(32or64位))
3、一个空类也一定有构造函数,析构函数,拷贝构造函数,赋值操作符重载(.text段)
7、应用
空基优化通常用于标准库类(std::vector, std::function, std::shared_ptr, etc)