(二)C++类的内存大小计算

释放双眼,带上耳机,听听看~!

计算一个类对象的大小规律:

    1、空类、单一继承的空类、多重继承的空类所占空间大小为:1(字节,用于标记对象地址);

    2、一个类中,虚函数本身、成员函数(包括静态与非静态)和静态数据成员都是不占用类对象的存储空间的;

    3、因此一个对象的大小≥所有非静态成员大小的总和(包括动态分配的变量…);

    4、当类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针vPtr指向虚函数表VTable;

    5、虚继承的情况:虚继承的实现是通过一个虚基类指针列表;由于涉及到虚函数表和虚基表,会同时增加一个(多重虚继承下对应多个)vfPtr指针指向虚函数表vfTable和一个vbPtr指针指向虚基表vbTable,这两者所占的空间大 小为:8(或8乘以多继承时父类的个数);

    6、在考虑以上内容所占空间的大小时,还要注意编译器下的“补齐”padding的影响,即编译器会插入多余的字节补齐(对齐规则见下面);

    7、类对象的大小=各非静态数据成员(包括父类的非静态数据成员但都不包括所有的成员函数)的总和+ vfptr指针(多继承下可能不止一个)+vbptr指针(多继承下可能不止一个)+编译器额外增加的字节。

一、非虚单继承

计算顺序:
父类大小(虚函数指针+数据成员)自己数据成员大小

底层原理可以理解为:

1、子类继承了父类的虚函数表和虚函数表指针。

2、若子类重写了父类的虚函数,则更新虚函数表中虚函数的地址为重写后函数地址。

(二)C++类的内存大小计算

二、非虚类多继承

计算顺序:从左到右计算父类大小(父类计算方法:
虚指针大小自己数据成员大小)
自己数据成员

底层原理可理解为:

1、子类继承了各个父类的虚函数表和虚函数指针(每个父类都有单独的虚函数指针和虚函数表)

2、
子类将自己的虚函数信息更新到第一个父类的虚函数表中

(二)C++类的内存大小计算

三、虚继承的钻石继承:

计算顺序:从左到右计算直接父类大小(父类大小计算方法:虚函数指针+虚基类指针+成员数据)
自己的数据最顶层父类的虚虚函数指针(前提是虚函数)最顶层父类数据

(二)C++类的内存大小计算

 

综上总结:

1、单个类大小 = 虚函数表指针(如果存在虚函数)+数据成员大小

2、非虚继承(包括:单继承、多继承)场景:

子类继承第一个父类的虚函数表和虚函数指针,并更新第一个父类的虚函数表。

子类大小 = 各父类大小(从左右,父类计算包括虚函数指针) + 子类自己成员函数大小

3、虚继承场景:

1)中间派生类大小 = 虚函数表指针+虚基类表指针+数据成员大小

2)子类大小 = 各父类大小(从左右,父类计算包括虚函数指针、
虚基表指针) + 子类自己成员函数大小+最顶层父类大小

 


C++内存对其规则:

1、第一个数据成员放在offset为0的地方,以后每个数据成员的对齐按照#pragma pack指定的数值和这个数据成员自身长度中,比较小的那个进行(只要存放位置是这个值得整数倍)。

2、在数据成员完成各自对齐之后,类(结构或联合)本身也要进行对齐,对齐将按照#pragma pack指定的数值和
结构(或联合)最大数据成员长度中,比较小的那个进行。

很明显#pragma pack(n)作为一个预编译指令用来设置多少个字节对齐的。值得注意的是,n的缺省数值是按照编译器自身设置,一般为8,合法的数值分别是1、2、4、8、16。

即编译器只会按照1、2、4、8、16的方式分割内存。若n为其他值,是无效的。


二、在没有#pragam pack宏的情况下,struct/class/union内存对齐原则有四个:
1、结构(struct)或联合(union)的数据成员,第一个数据成员放在offset为0的位置,以后
每个数据成员存储的起始位置都是放在该数据成员大小的整数倍位置。如在32bit的机器上,int的大小为4,因此int的存储位置都是从4的整数倍的位置开始存储的。
2、
结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其
内部“最宽基本类型成员”的整数倍地址开始存储(struct a里面有struct b,b里面有char、int、double等元素,那b应该从8的整数倍位置开始存储)。
3、结果体的
总大小,也就是sizeof的结果,必须
是其内部最大成员的“最宽基本类型成员”的整数倍,不足时要补齐。(基本类型不包括struct、class、union)
4、sizeof(union),以结构里面size最大元素为union的size,因为在某一个时刻,union只有一个成员真正存储于该地址。

给TA打赏
共{{data.count}}人
人已打赏
安全技术

C/C++内存泄漏及检测

2022-1-11 12:36:11

安全运维

java操作Redis

2021-12-11 11:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索