【读书笔记】《深度探索C++对象模型》

182 阅读5分钟

去年年底就已经看完这本书了,想着整理读书笔记一直拖延到现在,体验就是没有整理出来的知识过的久了确实容易忘记。

第1章 关于对象

  1. C++相对于C来说,在布局以及存取时间上的主要的额外负担是由virtual引起的。
  2. 三种对象模型:
    • 简单对象模型:member本身不放在object之中,只有“指向member的指针”才放在object内。该模型没有用在实际产品上。
    • 表格驱动对象模型:将class object拆分成data member table和member function table,class object存放指向这两个table的指针。该模型没有用在实际产品上。
    • C++对象模型:Nonstatic data members放在每一个class object之内,static data members,static/nonstatic function members则存放在个别的class object之外。
  3. virtual function的实现机制:
    • 每个class产生一组指向该class的virtual functions的指针,存放在一个virtual table里(vtbl)
    • 每个class object有一个指针(vptr)指向相关的virtual table。vptr的设定和重置由class的constructor, destructor和copy assignment运算符自动完成。vtbl的第一个slot通常是class关联的type info object(用来支持runtime type identification)
  4. class对象占用的内存:
    • nonstatic data members的总和大小
    • 内存对齐损耗
    • 因支持virtual function产生的内存损耗

第2章 构造函数语义学

  1. 以下四种情况,编译器会为未提供默认构造函数的类合成默认构造函数:
    • 带有Default Constructor的Member class Object:类的成员变量有其他类,并且该类有默认构造函数;
    • 带有Default Constructor的Base Class:有父类,父类有默认构造函数;
    • 带有一个Virtual Function的Class:有虚函数;
    • 带有一个Virtual Base Class的Class:有虚基类; 编译器合成的默认构造函数并不会给nonstatic data member(如整数,整数指针,整数数组等)初始化!!!
  2. 成员初始化列表:
    • 初始化顺序是按照成员变量的声明顺序初始化的,编译器优化之后的顺序与成员列表的顺序不一定一致;
    • 成员初始化的code会放在实际code之前。

第3章 Data语意学

  1. 一个virtual base class subobject只会在derived class中存在一份实例,不管它在class在继承体系中出现了多少次。
  2. static data member存放在程序的数据段里,nonstatic data members存放在class实例里。

第4章 Function语意学

  1. name mangling的做法编译器并不统一,即生成的名字规范都不一致。编程中link出错的时候报出的奇奇怪怪的函数名其实就是经过name mangling的名字。
  2. static member function没有this指针:
    • 不能直接存取其class的nostatic members;
    • 不能声明成const, volatile或者virtual;
    • 不需要class object就能调用。
  3. 一个class只会有一个virtual table,virtual table中含有以下active virtual functions:
    • 该class定义的virtual function;
    • 继承自base class的virtual function;
    • 一个pure_virtual_called()函数实例。

第5章 构造,析构,拷贝语意学

  1. object生命周期:
    • local object从定义到退出其scope;
    • global object存活整个程序周期;
    • heap object从new开始到delete结束。
  2. vptr初始化的时间为base class constructors调用结束之后,程序员代码或者member initialization list之前。
  3. 以下情况下,class对默认的copy assignment operator不会表现出bitwise copy语意,即默认的拷贝赋值函数不太行:
    1. 当class含有一个member object;
    2. 当class的base class有一个拷贝赋值函数;
    3. 当class声明里任何virtual function;
    4. 当class继承一个virtual base class。
  4. 析构函数的实际顺序
    1. 析构函数本体;
    2. 如果class有member class object且拥有析构函数,则按照声明顺序相反顺序调用;
    3. 如果有vptr, 需要被重新设定,指向base class的virtual table;
    4. 如果有任何直接nonvirtual base classes拥有析构函数,会按照声明顺序的相反顺序调用;
    5. 如果有任何virtual base classes拥有析构函数,并且当前class为最末端的class, 则会按照原来构造的顺序的反顺序被调用。

第6章 执行期语意学

  1. 编程规范中建议object使用时才定义是因为可以节省非必要的对象产生和摧毁操作。比如说一个object先定义了,但其实后面并没有用到,编译生成的代码其实在定义出就产生了其构造,后面跳出scope又要产生其析构代码,这部分代码是冗余代码。
  2. new运算符:
    1. 配置内存;
    2. 在配置的内存处构造object,赋初值。

第7章 站在对象模型的尖端

  1. Template不好用,容易出错,debug麻烦,对编程人员要求很高。
  2. Template函数中涉及类型相关的校验,延迟到实例化操作时才发生。
  3. 发生exception时,编译器会做如下操作:
    1. 检验发生throw的操作的函数;
    2. 决定throw操作是否发生在try区段中;
    3. 若是,把exception type拿来和每一个catch子句进行比较;
    4. 如果匹配,流程控制交到catch子句中;
    5. 如果throw操作没有发生在try区域或者没有匹配到catch子句,编译器需要(a)摧毁所有active local object(b)将目前的函数从堆栈中unwind掉(c)进入函数调用栈下一个函数中,重复步骤2-5
  4. 对一个class指针进行dynamic_cast:
    1. 如果操作成功,则会返回真正的地址;
    2. 否则返回0,便是没有cast成功。