zoukankan      html  css  js  c++  java
  • 《inside the c++ object model》读书笔记 之三:Data语意学

    Data语意学

    ...引子:

      C++对象模型尽量以空间优化和存取速度考虑来表现nonstatic data members,并且和C语言struct保持数据配置的兼容性,它把nonstatic data members 直接存放在每一个class object之中,对于继承而来的nonstatic data members(无论是virtual或是nonvirtual base class)也是如此,不过并没有强制定义其空间排列顺序,至于static data members,则被放置在程序的一个global data segment中,不会影响个别的objects的大小,static data members永远只存在一份实体(对于template class的static data members情况稍有不同).
      每一个class object 必须有足够的大小,有时会很大,因为:
      1)由编译器自动加上的额外data members,用以支持某些语言特性(主要是各种virtual 特性).
      2)因为alignment的需要.

    3.1 Data Member的绑定:
    ...一个inline函数实体,在整个class声明未被完全看见之前是不会被评估求值的,如果一个inline函数在class声明之后立刻被定义的话,那就还是会对其评估求值的.
      但是,对于member function的argument list并不为真,argument list中的名称还是会在它们第一次遭遇时被适当地决议完成,所以extern 和nested type names之间的非直觉绑定还是会发生,因此,应该始终把"nest type 声明"放在class的起始处.

    3.2 Data Member的布局:
    ...C++ Standard规定,在同一个access section(如public,private...)中,members的排列只需符合"较晚出现的members在class object之中有较高的地址即可",也就是说各个members不一定连续排列,在这之间可能有alignment填补的一些bytes,同时编译器可能会合成一些内部使用的data members,以支持整个对象模型(如vptr).

    3.3 Data Member存取
    1)static data members
      static data members被编译器提出与class之外,并视为一个global变量,每一个member的存取许可,以及class的关联并不会导致任何空间是或是执行时间上的额外负担-无论是在个别的class objects或是static data member本身,这是通过一个指针和通过一个对象来存取member,结论完全相同的唯一情况.
      为了解决static data member的命名冲突问题,一般采取name-mangling手法.

    2)nonstatic data members
      nonstatic data members直接存放在每一个class object之中,除非经由明确的(explicit)或是暗喻的(implicit)class object,没有办法直接存取它们.
      就存取效率来说,因为对于每一个nonstatic data member 的偏移量,在编译时期即可获知,甚至如果是一个base class subobject(派生自单一或是多重继承串连)也是一样,因此存取一个nonstatic data member和存取一个C struct member在效率上没有差别,但是对于虚拟继承,如果存取的变量正是从一个virtual base class中继承而来的member时,其效率就会差一些.

    3.4 "继承"与data member
    ...在C++继承模型中,一个derived class object所表现出来的东西,是其自己的members加上其base classes members的总和,至于derived class members和base classes members的排列顺序在C++ Standard并未强制规定,对于大部分编译器来说,base class membes总是先出现,但是属于virtual base class的除外.

    1)单一继承并且不含有多态:
      一般而言,单一无多态的继承并不会增加空间或是存取时间上的额外负担,但是把一个class分解为两层或是多层,有可能会为了"表现class体系之抽象化"而膨胀所需的空间,C++语言保证"出现在derived class 中的base class subobject保持其完整原样性",所以,有可能因为alignment填补的空间在derived class保持其原来的大小,而导致derived class的空间膨胀,这就会导致一些非预期的结果发生.

    2)加上多态:
      加上多态以后带来的空间和时间上的负担:
      1)导入一个virtual table,用来存放它所声明的每一个 virtual functions的地址,这个table的元素数目一般是被声明的virtual functions的数目在加上一两个slots(用以支持runtime type identification).
      2)在每一个class object中导入一个vptr,提供执行期的链接,使每一个object能够找到相应的virtual table.
      3)加强constructor使它能够为vptr设定初值,让它指向class所对应的virtual table.
      4)加强destructor,使它能够摸消"指向clas之相关virtual table"的vptr,vptr很可能已经在derived class destructor 中被设定为derived class的virtual table的地址.

    ...对于vptr的位置:在C++2.0以后由于虚拟继承和抽象基类的出现使得vptr,一般会被放置在class的起始处.

    3)多重继承:
    ...对于多重继承其复杂度在于derived class和其上一个乃至于上上一个base class......之间的"非自然"关系.

    ...对一个多重派生的对象,将其地址指定给"最左端(也就是第一个)base class",情况和单一继承时相同,因为二者都指向相同的起始地址,至于第二个和后继的base class的地址指定操作,则需要将地址进行一下修改,加上或是减去介于中间的base class subobjects大小.

    ...对于存取第二个(或后继)base class中的一个data memeber的效率问题,由于members的位置在编译时就固定利率,因此存取members只是一个简单的offset运算,就像单一继承一样简单,不管是经由一个指针,reference,或是一个object来存取.

    4)虚拟继承:
    ...一般虚拟继承的实现方法是,如果class内涵一个或是多个virtual base class subobject,将被分割为两个部分:一个不变局部和一个共享局部.
      不变局部中的数据,不管后继如何衍化,总是拥有固定的offset,所以这一部分数据可以被直接存取,至于共享局部,所表现的就是virtual base class subobject.这一部分的数据,其位置会因为每次的派生操作而有变化,所以它们只能间接存取,各个编译器的差异就在于间接存取的方法不同.
      一般的布局策略是先安排好derived class的不变部分,然后在建立其共享部分.
      在这中间如何存取class的共享部分是问题的关键,对于virtual base class的模型的实现有两种方法,一种是Microsoft 编译器的做法,就是引入所谓的virtual base class table,每一个class object如果有一个或是多个virtual base classes,就会有编译器安插一个指针,指向virtual base class table,真正的virtual base class指针,就被放在该表格当中,还有一种就是在virtual function table中放置virtual base class的offset(不是地址).

    注:一般而言,一个抽象的virtual base class没有任何data members.

    3.5 指data members的指针:
    ...取一个类的nonstatic data member的地址,得到的将是该数据成员在类中的偏移量,然而,实际得到值是该数据的偏移地址加一,这个问题在于,为了区分一个"没有指向任何data member"的指针和一个指向"第一个data member"的指针,每一个真正的member offset的值都被加一(在vc++ 2008中,没有加一).

    ...取一个"nonstatic data member"的地址将会得到它在class中的offset,取一个"绑定与真正class object身上的data member"的地址,将会得到该member在内存中的真正地址.

  • 相关阅读:
    Java+7入门经典 -1 简介
    优化算法动画演示Alec Radford's animations for optimization algorithms
    如何写科技论文How to write a technical paper
    开始学习深度学习和循环神经网络Some starting points for deep learning and RNNs
    用500行Julia代码开始深度学习之旅 Beginning deep learning with 500 lines of Julia
    用10张图来看机器学习Machine learning in 10 pictures
    ICLR 2013 International Conference on Learning Representations深度学习论文papers
    ICLR 2014 International Conference on Learning Representations深度学习论文papers
    卷积神经网络CNN(Convolutional Neural Networks)没有原理只有实现
    卷积神经网络Convolutional Neural Networks
  • 原文地址:https://www.cnblogs.com/suiyu/p/2508910.html
Copyright © 2011-2022 走看看