-
参考链接
-
总览
- 主要介绍对象的内存布局.
- 比如对齐,偏移,虚表,虚表在内存位置等.
- 关于一个类的信息,都在
ABI
中,可以随时访问.
-
基本概念
-
sizeof(O)
- 关键字表示某个对象占用字节.
- 比如
sizeof(int) == 4
一样.
-
align(O)
- 关键字表示某个对象的对齐是多少.
C
语言中的字节对齐,比如1,2,4,8
字节对齐.
-
offset(C)
- 表示在对象
O
中,成员变量C
相对于第一个的偏移量.
- 表示在对象
-
小结
- 前面的这些信息在编译后都可以知晓.
- 在执行时也可以知晓.
- 对一个类即成员变量都有相关信息的记载.
-
dsize(O)
- 也就是
sizeof(O) = dsize(O) + padding
. padding
即为了对齐在对应位置进行补齐.
- 也就是
-
nvsize(O)
- 也就是去掉虚继承的类的大小.
virtul
继承的类,包括父类用virtual
继承的某个祖父类.
-
nvalign
- 去掉
virtul
父类后的对齐.
- 去掉
-
-
POD
数据类型 -
成员指针
-
成员变量指针
int T::*varname = &T::member
;- 访问就可以通过对象访问.
T().*varname;
- 在
ABI
中,其属性使用ptrdiff_t
记录. 即某个成员在某个类的内存布局中的偏移量. - 注意区别空指针和偏移量为
0
.虽然两者值都一样. 一般来说,用-1
表示空指针,而不应该用NULL
表示. - 但是
-1
也是可能的,比如,用父类的成员指针,通过偏移量,强转之类,计算前一个父类的成员. 这种不建议,也不合适. - 强转加上偏移量虽然也可以获取. 但是不建议.
- 直接进行偏移量的加减以此访问前后的数据虽然也可以,但是也不可取.
- 注意:
virtual
类型的类型转换不支持. TODO
- 总结: 成员变量指针的值是偏移量,解引用则是进行加减.
-
成员函数指针
- 不同平台实现不同.
- 一般是用
struct{fnptr_t ptr;ptrdiff_t adj;}
,ptr
表示函数位置.adj
表示对象位置. ptr
是虚函数,则是1+offset_in_vtable
,如果是普通函数则是地址.+1
是为了区分空指针.0
表示空指针,1
表示偏移量为0
.在调用的时候加进来.adj
则是表示在调用之前,需要添加对应的偏移量.指针指向对应函数的对应对象.- 影响结构体和指针实现的依据:
- 函数地址低位为0,这个很多都没有实现,这个依赖平台.
- 虚函数中,空的函数指针必须要和偏移量为
0
区分. 前面介绍了+1
的操作规避. - 函数在虚表中的偏移量不会是奇数. 这种也和实现有关,有的可能指针没有对齐,或者指针是奇数位.
- 虚函数调用,在仅仅知道偏移量和类型的时候也可以调用. 大多都可以,偏移加上虚表首地址定位到对应位置存放的函数指针.
- 可以进行指针的加减运算,以获取某个函数. 注意: 是否可以用于访问
protected
的虚函数指针. - 执行函数调用:
adj += this
,以转移到正确位置.ptr
的转换,得到函数对应地址.
-
-
非
POD
类类型-
简介
- 即一个类不符合
POD
规定,即C++
风格的类. - 下面就是介绍这类数据的内存布局.
- 即一个类不符合
-
背景
C
类型的类,这个类C
不符合POD for the purpose of layout
的定义.- 并且,假设
C
的所有的信息已经处理,即成员变量和父类的size,dsize,nvsize,alignment,nvalign
都已经明确. - 那么下面就介绍如何将这些组合成一个新的,符合规范的类
C
的内存布局. - 父类和成员都已经明确,但是自己还没有明确的组装好.下面就开始分析怎么组装.
-
1.Initialization
- 先将
C
的相关信息初始化为0
. -
- 如果
C
是一个多态类.
- a. 找到父类中直接或间接继承的
virtual
类,从中赛选出是primary base class
的类. 将这列命名为indirect primary base class
,即间接的主类. - b. 如果
C
有一个类是多态类,从这些类中找出一个符合条件的类B
作为primary base class
,即公用一个virtual table
. 先从直接父类中,非virtual
继承的里面找符合条件的.如果一个都不符合,找广度优先遍历找到的第一个nearly empty base class
作为primary base class
,同时这个类还需要满足不是indirect primary base class
. 最后则从indirect primary base class
中找第一个作为primary base class
. - c. 如果
C
还是没有找到primary base class
,自己创建一个虚表,并初始化.
- 如果
- 前面
2.b
描述的设计现在看来有点问题. 将第一个indirect primary base class
作为C
的primary base class
并不会节约空间.甚至还会造成
- 先将
-
02 内存布局
猜你喜欢
转载自blog.csdn.net/rubikchen/article/details/121407854
今日推荐
周排行