深度探索C++对象模型——6_执行期语意学

1.对象的析构和构造

尽可能把object放置在使用它的那个程序区段附近,可以节省非必要的对象产生操作和消耗操作

1.1 全局对象

C++中所有的global objects都被放置在程序的data segment中。如果显式指定一个值,此object将以该值为初值,否则分配到的内存内容为0.
global class object 在编译时期可以被置于data segment中且内容为0,但constructor一直要到程序启动时才能实施。
(munch策略:一个可移植但成本颇高的静态初始化方法。)
使用静态初始化的objects,有一些缺点:

  • 1.如果exception handling被支持,那些objects将无法被放置在try区段内。因为任何throw操作必将触发exception handling library默认的terminate()函数。
  • 2.为了控制“需要跨越模块做静态初始化”的objects的相依顺序,而导致复杂度很高。

1.2 局部静态对象

语意:
该object的构造函数和析构函数只施行一次,虽然该class 的函数可能会被调用多次。
由于是static 故其地址会被转移到程序用来放置global object的data segment中。
local static class objects在需要时才被构造(如每一个含有该objects的函数第一次被进入时)然后按照构造的相反顺序析构。

1.3 对象数组

Point knots[10];
如果该class既没有定义一个constructor也没有定义一个destructor,那么只需要配置足够的内存以存储连续n个的class元素即可。
如果定义了一个default constructor和destructor那么创建和消耗时会轮流作用在那十个Point元素上。(在vec_new()中,constructor施行于elem_count个元素之上)
如果给部分进行了初始化,那么default construct会作用在剩下的元素上。

1.4 Default Constructors和数组

当构建class object数组时,如果constructor有一个或以上的参数,编译器会在内部产生一个stub constructor,没有参数,然后在其内部调用用户的那个constructor,并将default 参数值显式的传递过去。

2. new和delete运算符

运算符new的使用,实际上由两个步骤完成:

  • 1.通过适当的new运算符函数实例,配置需要的内存;
  • 2.将配置得来的对象设置初值。
    即初始化操作在内存配置成功后才执行。
    使用指针pi和使用pi所指的对象,差别在于哪一个的生命已经结束了。当释放掉pi所指的对象后,虽然地址上的对象不再合法,地址本身确代表一个合法的程序空间。因此pi能够被继续使用,但只能在受限制的情况下使用,很像一个void*指针的情况。
    如果以new运算符配置object,而其constructor抛出一个exception,配置得来的内存会被释放掉然后exception会被抛出去。
    语言要求每一次对new调用都必须传回一个独一无二的指针,解决办法是返回一个指向默认1-byte内存区块的指针。
  • new运算符实际上总是以标准C malloc()完成。
  • delete运算符也总是以标准的C free()完成。

2.1 针对数组的new语意

  • vec_new():主要功能是把default constructor 施行的class objects所组成的数组的每一个元素身上。
  • new运算符:完成普通的生成。
    如果一个class没有定义一个constructor或destructor,配置数组和释放内存的操作,由new和delete运算符来完成就足够了。
    如果class定义了一个default construct,某些版本的vec_new()就会被调用,配置并构造class objects所组成的数组。
    在个别的数组元素构造过程中,如果发生exception,destructor就会被传递给vec_new()。只有已经构造妥当的元素才需要destructor的施行(因为它们的内存已经被配置出来了,vec_new()有责任在exception发生时把那些内存释放掉)。
    在delete时:只有在[]出现时,编译器才寻找数组的维度,否则变假设只有单独一个objects要被删除,其他元素仍然存在。
    编译器如何确定应该删除多少?应该如何记录元素个数?
  • 法1:cookie策略:为vec_new()所传回的每一个内存区块配置一个额外的word,然后把元素个数放在那个word内。问题:如果一个坏指针本应该被交付给delete_vec(),那么其取出来的cookie自然是不合法的。一个不合法的元素个数和一个坏的起始地址,会导致destructor作用于一段非预期的区域内。
  • 法2:联合数组策略:维护一个联合数组,放置指针及大小。对于法1的问题,坏指针的可能结果就只是去除错误的元素个数而已。
    施行于数组上的destructor,是根据交给vec_delete()函数的“被定义的指针类型的destrctor”和元素大小。
    故一个bc指针指向了dc object会导致删除不正确。在这种情况下,程序员应该手动迭代释放。

2.2 Placement Operator new的语意

有一个预定义好的重载的new运算符,称为placement operator new.它需要第二个参数,类型为void*
(例:Point2w *ptw=new(arena)Point2w;)
其中arena指向内存中的一个区块,用以防止新产生的Point2w object。只要将获得的指针(即arena)所指的地址传回即可。
过程:将Point2w的constructor自动实施于arena所指的地址上。
如果在原有的一个object上构建新的object,并且那个object由destructor,那么需要先调用destructor保留空间在使用。

3.临时性对象

C++standard允许编译器对临时性对象的产生由完全的自由度。
T c=a+b;
实现时根本不产生一个临时性对象。
c=a+b;
会产生一个临时性对象。
故第一个总比第二个更有效率的被编译器转换。
a+b;//没有目标对象
临时对象的被销毁,应该是对完整表达式求值过程中的最后一个步骤。该完整表达式造成临时对象的产生。
完整表达式:是被涵括的表达式中最外围的那个。
临时性对象在完整表达式被评估完全之前,不得被销毁。
临时性对象的生命规则有两个例外:

  • 1.发生在表达式被用来初始化一个object时。这个临时性对象会保留到object的初始化操作完成为止。
  • 2.当一个临时性对象被reference绑定时。此时这个临时性对象会保留到reference的生命结束或临时性对象的生命范畴结束(看那种情况先到达。)

3.1 临时性对象的迷思

临时性对象的创建会导致程序效率的降低。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值