现在的位置: 首页 > 综合 > 正文

Inside C++ Object Model阅读笔记:Chapter 6

2018年03月31日 ⁄ 综合 ⁄ 共 1955字 ⁄ 字号 评论关闭
第六章 运行时语义学

6.1 对象的构造和析构
构造和析构函数成对形成。goto语句和switch语句,return语句可能产生多个析构。应该尽量在使用对象时才构造对象,可以节省构造时间。
对于全局对象,语言保证对象在main()的第一个语句之前构造并且在main最后一个语句之后析构。所有全局的对象如果没有给定初始值,则初始值被设为0(附注:与本地对象不同!另外C语言是不初始化的!)。
为了保证全局变量的初始化,cfront在main()的第一句之前插入了_main()进行相应的处理,调用所有__sti()(附注:static initialize)。同样,为了析构,在exit()中加入了对所有__std()的调用。
使用这样的对象的缺点有一些:不能被放置在try{}中,程序的不同模块中也会变得复杂起来。作者推荐不要使用全局对象。
本地静态对象将被保证只被构造一次,析构一次。C++在本地静态对象第一次使用时构造它,并且设置一个全局的标记位防止它再次被构造。同样,析构时将检查这个全局的标记位。
数组的构造首先需要申请相应的内存,然后调用无参数构造函数进行构造。一般编译器将使用一个vec_new函数解决这个问题。如果需要new抛出异常,则还必须准备一个析构函数以保证系统资源稳定。delete也有相应语意。对于给出了所有参数缺省值的构造函数,系统将生成一个对应的无参数构造函数用于数组的构造。

6.2 new和delete操作符
new包括两步:申请内存和初始化。只有申请内存成功才会进行初始化。delete在进行释放内存之前需要先检验指针是否为NULL(附注:所以无须if (p!=NULL) delete p;,语义学会解决这个问题。)delete并不将被释放的指针还原为0,因此仍然可以访问指针的内容,但是访问很可能会带来一些麻烦。
new和malloc的区别在于调用构造函数。new会主动调用构造函数初始化对象。如果存在异常处理,则new还会在构造函数抛出异常时传递这个异常。同时申请的内存还会被回收。
使用delete时析构函数将被调用,之后释放内存。如果异常处理存在则同样会抛出异常。
用new申请0大小的内存时,会产生一个1大小的对象。而且new允许对申请不到内存情况给出一个new_handler,用户决定处理的方法。
new总是用malloc实现,而delete也相应由free实现。
在有数组的情况下:如果没有构造函数的对象,则直接申请内存。如果有构造函数,则会调用vec_new,将构造函数和析构函数的地址传入(附注:Lipperman刚刚才说过构造析构函数不能取址啊我的天啊!)给出析构函数的原因是,如果构造单个函数失败,则会析构之。对数组的delete需要加上操作[],不需要加上参数大小。如果没有[],虽然内存被释放,但是只有第一个对象的析构函数被调用。
特别需要注意,delete中会调用和指针对应的类型的析构函数,这就是说,如果用基类指针类型指向一个数组,则delete时调用的是基类指针的析构函数。(附注:真的震惊了一回!为什么不在new前面加上typeinfo解决这个问题呢?)
对于一种特殊的操作符new,给定位置的new将有一个新的参数,一个void*指针,以确定新对象在内存中的位置。new负责在此处调用构造函数以构造这样的一个对象。为了释放这样的一个对象而不释放相应内存,用到了一个相应的delete负责调用析构函数。这个new不负责检查在给定位置是否已经有一个对象存在,也不负责检查void*指针原来是什么类型的指针。如果派生类的对象被构造在一个基类的对象上(假设派生类不含数据成员),那么对对象的操作将是不可知的。

6.3 临时变量
在T c=a+b中往往存在NRV优化,这时没有临时变量存在。而c=a+b中则必然有临时变量。对于单独的a+b,或者s+t+v,则必然有临时变量存在。临时变量的生存期依赖编译器实现。标准规定临时对象在语义学角度中,对包含它们的整个表达式的最后运算后被破坏。
有两种例外。一种是用于构造一个对象:
bool verbose;
string prognamever=verbose ? 0 : progname+progversion;
这里用于储存progname+progversion的临时变量的生命周期不会仅仅局限在?:操作之中,而会延长到整个string构造的生命周期。
第二个是引用的对象:
const string& space=" ";
这里会形成一个临时对象string(" "),它的生命周期和space相同,或者临时变量的作用域结束,二者取先到达者。
C++的临时变量大大降低了效率,在对象作为变量传递时应该尽量使用引用而非值,除非用到inline。
(附注:作者举了一个有趣的例子,不记录)

抱歉!评论已关闭.