C++必看:很重要的C++内存对齐模型

内存模型问题

  1. 空类和空结构体的sizeof
    • 在C++中,一个空类(class)或空结构体(struct)没有任何数据成员时,sizeof为1字节。
    • 这是因为C++要求每个对象占用至少1字节的空间,以确保每个对象有唯一的内存地址。
  2. 类和结构体的相同点
    • 在C++中,classstruct在内存布局和功能上几乎等价,唯一的区别是默认访问权限:
      • class默认是private
      • struct默认是public
    • 因此,空类和空结构体的sizeof行为完全一致
  3. 添加普通成员函数
    • 为空类或空结构体添加普通成员函数(包括构造函数、析构函数等)不会改变sizeof,仍为1字节
    • 原因:成员函数是类的行为,存储在代码段中,不占用对象实例的内存
  4. 添加虚函数
    • 当空类或空结构体添加第一个虚函数时,sizeof会增加到虚表指针(vptr)的大小:
      • 32位系统:通常为4字节
      • 64位系统:通常为8字节
    • 添加多个虚函数不会进一步增加sizeof,因为只需要一个虚表指针指向包含所有虚函数地址的虚表。
  5. 结构体支持成员函数
    • C++中的struct可以像class一样添加各种成员函数(普通函数、构造函数、析构函数、虚函数等),并支持面向对象特性(如继承和多态)。
    • 这是C++对C语言struct的扩展,使其功能与class等价。
  6. 关键结论
    • 空类和空结构体的sizeof默认是1字节。
    • 普通成员函数不影响大小,虚函数引入虚表指针后大小变为4或8字节(取决于平台)。
    • 无论class还是struct添加多个虚函数只增加一个虚表指针的开销,不会随虚函数数量线性增长。

结构体对齐

  • 由于系统资源分配的问题,结构体占用的内存字节数并不总是所有的结构体成员的内存之和,而是会大于等于结构体成员的内存,便于提高运行效率
  • 运行结果总是结构体中对齐要求的整数倍
  • 对齐的要求为min(8, 最大成员占用的的字节数),8是指的64位系统
#include <iostream>
using namespace std;

struct s1
{
    char c1; //1b  0
    int i; // 4b   4
    char c2; //1b  8
};

struct s2
{
    char c1; // 1b  0
    char c2; // 1b  1
    int i; //4b     4
};

struct s3
{
    char c1; //1b  0
    int i; // 4b   4
    char c2; //1b  8
    char c3; //1b  9
};

int main(int argc, char const *argv[])
{
    cout << sizeof(s1) << " " << sizeof(s2) << " " << sizeof(s3) << endl;
    
    //打印偏移量
    cout << offsetof(s3, c1) << " " << offsetof(s3, i) << " " << offsetof(s3, c2) << " " << offsetof(s3, c3) << endl;
    return 0;
}
  • 运行结果

    12 8 12

    0 4 8 9

  • 对于不同位数的成员,只能存放在指定位置:char 0 1 2 3… int 0 4 8 12… double 0 8 16

  • 所以结构体的利用规则:体积小的永远零接着放,便于节省空间

  • 对于嵌套的结构体,需要仔细辨认,结构体嵌套,嵌套的结构体对齐到自己的最大对齐数,将结构体放入新的结构体,新结构体对齐到所有的最大对齐数(把嵌套的结构体当成员考虑)

#include <iostream>
struct s1
{
    double d;
    char c;
    int i;
}; //16

struct s2
{
    char c1; //0
    struct s1 s; 
    double d; 
};

/*
struct s2
{
    char c1; //0
    
    //s1的代码
    double d; //8
    char c;   //16
    int i; //20
    
    double d; //24
    -->24+8 = 32
};

*/
int main(int argc, char const *argv[])
{
    std::cout << "sizeof(s1): " << sizeof(s1) << std::endl;
    std::cout << "sizeof(s2): " << sizeof(s2) << std::endl;
    return 0;
}
  • 运行结果

    sizeof(s1): 16
    sizeof(s2): 32

  • 通过宏指定对齐数#pragma pack(1),指定对齐为1字节(老版本)

  • 新版本用alignas()或者alignattribute,不同的编译器标准不同

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值