之前看八股的时候,简略看了一下结构大小的问题,现记录一下
// 64位系统
#include<iostream>
using namespace std;
struct Test
{
int a;
char b;
};
int main(){
cout<<sizeof(Test)<<endl; // 输出8
return 0;
}
结构体和类的大小与什么有关
- 遵循内存对齐原则
- 类的大小只与普通数据成员有关(非静态成员变量)
- 虚函数类会增加虚函数表指针的大小
- 虚继承类会增加虚基指针的大小
- 空类大小为1
内存对齐问题
什么是内存对齐?
计算机系统对基本数据类型在内存中的存放有限制,会要求这些数据的首地址的值是某一个值(有效对齐值)的整倍数,这样便于存取。
为什么要内存对齐?
有了内存对齐和有效对齐值,操作系统就可以一次读出特定的值,而不用进行“拆分”
有效对齐值
尽管字节是最小的内存单位,但是处理器不会按照字节大小来存取内存(毕竟大部分的基本数据类型都是4字节、8字节等),例如,如64位操作系统下的存取单位是8,也叫默认“对齐系数”
#pragma pack(8) // 64位系统
而有效对齐值则是需要用结构体的值与默认对齐系数进行比较
有效对其值:是给定值#pragma pack(n)和结构体中最长数据类型长度中较小的那个。有效对齐值也叫对齐单位。
举个栗子
#include<iostream>
using namespace std;
#pragma pack(8) // 64位系统下
struct Test1
{
int a[5]; // 4*5 = 20
int *b; //
};
struct Test2
{
int a[5]; // 4*5 = 20
int &b; // 64位是8
};
struct Test3
{
int a;
char b;
};
int main()
{
cout<<"结构体Test1占用的内存空间字节大小为:"<<sizeof(Test1)<<endl; // 32
cout<<"结构体Test2占用的内存空间字节大小为:"<<sizeof(Test2)<<endl; // 32
cout<<"结构体Test3占用的内存空间字节大小为:"<<sizeof(Test3)<<endl;// 8
}
好,内存对齐讲完了,大概就是这样.
对于内存对齐,只需要先计算出有效对齐值,再按照声明顺序在内存中排兵布阵就行.
但是,上面有一个很有意思的东西,结构体Test2中有一个int &b,相信有人会疑惑三连问了
这个不是引用吗?
引用不是需要初始化吗?
引用不是只是别名吗?怎么会有大小?
慢慢来解析!
引用的问题
左值右值引用我就不说了,网上有太多博客介绍
首先引用需不需要初始化,在我们之前的观念中,引用是一个对象的别名,如果对象都没有,就别谈别名了
int main() {
int a = 10; // 左值 对象
int &b = a; // 左值引用 对b起别名
return 0;
}
但是!为什么结构体里可以不用初始化呢?也没有报错?
原因是,结构体Test2里的对象不是定义,而是声明(类也可以,类内声明,内外定义)
而声明则是不会为对象分配空间!所以不会报错
#include <iostream>
extern int& c;
struct Test{
int a;
int &b;
};
int main() {
int a = 10; // 左值 对象
int &b = a; // 左值引用 对b起别名
Test t; // note: ‘int& Test::b’ should be initialized
c = a; // 声明之后再定义就没错
return 0;
}
但是实例化之后就会出错!
引用的大小问题
一般我们对引用sizeof()的话,都是计算其指向对象的大小,但是声明没有指向对象,在内存中也会分配空间(如果能合法执行的话)
#include <iostream>
using namespace std;
struct Test{
int a;
int &b;
};
int main() {
int a = 10; // 左值 对象
int &b = a; // 左值引用 对b起别名
cout<<sizeof(a)<<endl; // 4
cout<<sizeof(b)<<endl; // 4
cout<<sizeof(Test)<<endl; // 16
}
在结构体里的引用声明大小和指针类型一样!
c++真的是…太神奇了!