01 常规概念

  1. 参考链接

  2. 简介

    • 开发这个文档最开始由大几个公司起草。
    • 也有一些独立开发者的加入,后来就开源了。
    • 部分编译器的开发者按照了这个文档的规则进行实现C++编译器.
  3. 内容

    • 基本内容

      • 主要是介绍C++ABI: 介绍不同编译器,不同用户提供的代码段在编译链接,预加载和执行时的交互.
    • 主要内容

      • 介绍C++中,数据内存布局.
      • 包括: 预定义内置数据,用户定义数据,编译器生成数据(虚表之类的).
      • 还会介绍函数调用,异常处理,函数命名,对象内存规范和布局.
    • 须知

      • 主要为新平台实现C++编译器提供了一个简单的思路.
      • 这个文档也是在C ABI的基础上编写.
      • 同时,这个文档是基于itanium架构处理器进行编写.部分内容还是基于itanium的基础进行说明.
    • 最后

      • 这个文档是参考,并不是官方.
  4. 关键字定义

    • alignment of a type T (or object X)

      • 指的是类型T或者对象X的字节对齐是多少.
      • 1,2,4,8字节对齐.
      • 一般来说,一个结构体或类按照某字节对齐,那么这个对象所在地址,一般也是可以整除的.
      • 比如类型T按照8字节对齐,那么对于T X,&X & 7 == 0.
    • base class of a class T

      • 类型T的所有父类.
      • 这里base class指的是T以及其父类.
    • proper base class of a class T

      • 这里则是上面的特殊版本,不包含T本身.
      • 即指的是T的所有父类.
    • virtual base class of a class T

      • T通过virtual继承的. struct T:virtual X
    • base object destructor of a class T

      • T的基本析构函数.
      • 主要的功能: 为T声明的非static成员变量执行析构的函数. 同时还包括其直接父类,直接父类不包括virtual继承的.
      struct A{};
      struct B{};
      struct C{A a;};
      struct T:public A,public B,virtual public C{
         static A a;
         B b;
      };
      
      • 在上面的案例中base object destructor的构建结果应该是:
      • b的析构函数,a是静态不纳入其中.
      • 继承下来的A,B,调用其析构.Cvirtual继承来的.
      • 最后: 析构里面只处理直接继承的父类,父类的父类则有父类来处理.递归式的.
      • 说明: 现在的编译器把自定义和默认的都放在一起了.
    • basic ABI properties of a type T

      • 类型TABI中的基本信息.
      • 即一个类,在最终生成了之后,会为这个类添加对应的数据,已记录其数据的有效性和数据布局,数据对齐等信息.
      • 这里是对类在ABI中的布局描述.
    • complete object destructor of a class T

      • 这里则是完整的析构函数,即自定义的析构函数.
      • 即前面的base object destructor of a class T加上额外的.
      • 额外的就是用户自定义的,比如析构指针之类的.
      • 所以用户自定义的在base object destructor of a class T的前面执行.
    • deleting destructor of a class T

      • 则是complete object destructor of a class T加上额外的.
      • 这里的额外就是对delete进行了重载的函数.
      • delete在最前.没有的话就是默认的空.
    • direct base class order

      • 直接继承的顺序.
      • 如前面的案例struct T:public A,public B,virtual public C.
      • 这里就是直接继承顺序就是:从左往右. 不同的实现可能不一样,可能是按照逆序.
    • diamond-shaped inheritance

      • 菱形继承,百度一大堆.
      • 简单说就是把继承关系图画出来,是一个菱形.
      • 当然,这里说的菱形是特殊了,可能最终画出来也不是标准菱形.只是因为最简单的案例画出来确实就是菱形.
    • dynamic class

      • 多态类.
      • 即一个函数中有虚表.
      • 虚表则说明这个类:
      • 普通继承public,protected,private继承的父类里面有一个virtual函数.
      • 也可能是struct T:virtual A,即virtual的方式继承,也有.
      • 所以避免菱形继承的子类肯定有虚函数指针.是一个多肽类.
    • empty class

      • 空的,假如T就是一个empty class,那么sizeof(T) == 1.
      • 为什么等于1,因为这是编译器这么做的,如此可以保证定义两个类,所在位置不一样,有一个唯一的地址.
      • 空类的特性就是: 可以有static成员,但是不能有普通成员.
      • 如果有普通成员,那么其必然是type name:0;这种,也可以是type :0;,也可以是type s[];,这几种没有不占空间的类型.
      • 可以有成员函数,但是不能有virtual类型的.
      • 可以继承,但是其继承的父类也必须是empty的.
      • 当然也不可以virtual继承.
      • 总之: 最终大小为1.
    • empty data member

      • data member,即没有成员变量. 这里不要求sizeof(T) == 1.
      • 要求当前类没有数据成员变量,可以有virtual函数,可以有static,就是不能有成员变量.type name:0;这类也不行. 可以有父类。
      • empty class的交际就在于,没有自己的成员变量。但是其他的都可以有。
    • inheritance graph

      • 继承图,即将所有父类罗列出来,按照继承关系连接起来,形成的有向拓扑图.
      • 就是最终的继承图.
      • 菱形继承里面的案例图就是一个继承图.
    • inheritance graph order

      • 继承顺序,遍历前面的inheritance graph,按照深度优先遍历.大多数都是这样.从子类到父类.
      • 所有的结点只遍历以此. 尽管virtual继承的可能出现多次,但是只遍历一次. 父类的顺序按照先后顺序从左往右遍历.
      • 比如class A:public B,public C就是A -> B -> C. 这里的遍历是按照print,visit,visit的方式遍历.
      • 这里的继承顺序和内存布局无半毛钱关系,但是可以在内存布局的时候参考.
    • instantiation-dependent

      • TODO
    • morally virtual

      • XY的直接用virtual继承的或着所示,XY的父类通过virtual X继承的.
      • 那么XYmorally virtual.
      • XY 直接virtual继承的父类,或者说是其virtual继承父类的直接或间接的父类。可以规避菱形继承。
      • 名义上的虚基类.
    • nearly empty class

      • sizeof(T) != 1,且里面的数据都是指针. 即父类和自己都没有任何成员变量.全是虚函数和virtual继承.
      • 如下描述:
      • 没有成员变量,static的可以有.
      • 没有长度不为0的匿名字段,type name:0;可以. 不匿名就是成员变量了.
      • 最多只有一个直接非virtual继承的父类,即class T:public X.而且这个X同样是nearly empty class.
      • 所有的父类都不为空,所有父类都是virtual继承的, 且所有父类都公用一个虚表.
      • 这类最适合用来做primary base classes
    • non-trivial for the purposes of calls

      • 有意义的成员函数. 看成一个名词最好.参考https://quuxplusone.github.io/blog/2018/05/02/trivial-abi-101/
      • 有自定义的拷贝构造,移动构造,析构.
      • 或者拷贝和移动构造是delete.
      • 满足上述条件一个即可.
      • 目的:拥有上诉所设计的函数才能算是完整的定义。在进行临时变量的传递或者返回的时候,会执行对应的函数。如果没有,就是trival类型,那么就会根据ABI的定义,在传递或返回的时候,直接memcpy复制即可.
      • 总结: 有自定义拷贝移动构造和析构或删除了拷贝移动构造则是non-trivial. 否则就是 trivial ,就直接拷贝内容即可.
      • 主要还是和C区分,没有就用C对待,有就用C++对待.
    • POD

    • POD for the purpose of layout

      • 类型如果是POD类型,即plain old data,大多都满足.
      • 前面说了POD类型大多都满足,但是下面一个条件满足了,就不是POD for the purpose of layout:
      • pod类型的unionstruct,这两种类型中,如果存在一个成员变量的bit比自身的bit宽,那么就不是. int sss:33;,int 32位,而声明了33位.
      • 或者是一个数组,元素类型不是POD for the purpose of layout.
      • 或者是POD类型中,有几个非静态成员变量的地址不唯一,存在交叉.比如struct{int a:1;int b:2;int c:5;};,这里三个成员变量才占用一个字节.三个变量的地址公用.
    • potentially-overlapping subobject

      • 父类或成员变量声明了[[no_unique_address]]属性.
    • primary base class

      • 当前类和某个父类共享了虚表.这个虚表的拥有者就是primary base class.
      • 共享虚表可以介于空间.
      • 首先满足是多态类. 前面介绍的nearly empty class就适合用来选择primary base class.
    • secondary virtual table

      • 不是primary的虚表就是secondary.
      • 一个多态类可能有多个secondary virtual table. 因为可能父类中有好几个virtual继承,且没有选上primary base class的.
    • thunk

      • 汇编代码,不是函数,和某个方法或者说操作绑定.
      • 比如对于动态库中的符号,进行延迟绑定,就借助了一个thunk.
      • 这里一般用来修改this,进行偏移到正确的子类上操作. 或者说是将调用的函数修改为真正的函数,也可能在返回之后将值进行修改.
      • thunk应该尽量的短,太长了就建议作为函数创建,拥有自己的栈帧.
    • vague linkage

      • 属于编译阶段,特别是处理内联函数和模板以及虚表. 在obj中编译一个有一个,那么就需要在链接阶段去重.
      • 在编译的时候可以当成只有一个,而不是多个重复的. 具体可以去看《程序员的自我修养》,此书中有关于编译去重的介绍.
    • virtual table| vtable

      • 多态类一般都有一个关联的表,对象共用.
      • 这个表中存放了多态类的相关属性: 函数指针,virtual父类在内存中的偏移量等等.
    • virtual table group

      • 类本身的虚表和其所有父类的虚表.
      • primary base classtable + secondary virtual table.
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值