【C++对象模型】第六章 执行期语意学
执行期语意学,即在程序执行时,编译器产生额外的指令调用,确保对象的构造,内存的释放,以及类型转换与临时对象的生成的安全进行。
1、对象的构造和析构
对于类对象的构造,一般在定义之后则开始内部的构造过程。一个区段可能有多个return离开点,所以可能导致一些对象创建后,没有用就需要释放,这就造成了很多浪费。所以建议把object放置在使用它的区段的附近。
而对于已构造的对象,其析构函数必须放在每一个离开点(当object还存在)之前。
2、全局对象
对于全局变量,C++会保证在调用全局变量之前,将全局变量构造出来。
而所有的全局变量都被放置在程序的数据段中(data segment),并且为没有显示指定值的变量初始化为0.
同时对于全局的类对象,在编译时期被放置于data segment中并且内容也为0.只有在程序启动时其对应的constructor才会实施。因此object需要静态初始化。
静态初始化的munch策略:
- 为每个需要静态初始化的文件产生一个_sti()函数,内含必要的constructor调用操作和inline expansions。
- 为每一个需要静态的内存释放操作的文件,产生一个_std()函数。
- 提供一个_main()函数调用所有的_sti()函数,一个_exit()函数调用所有的_std()函数

3、局部静态对象
局部静态对象的constructor只能被施行一次,destructor也只有一次。
所以对于局部静态对象,一个很简单的思路就是导入一个临时性对象,当第一次传入时,设置为true,之后则不再进行处理。
void Point& identity()
{
staitc Point sta_Point;
return sta_Point;
}
不管该函数被调用多少次,静态局部对象sta_Point只会被初始化一次,理所当然也只会被析构一次,这种通过函数返回局部静态对象的方法通常是用来解决跨模块(文件)的全局变量的初始化顺序问题。
4、对象数组
对于以下数组定义:
Point knots[ ];
如果 Point未定义默认构造函数或者析构函数,那么产生该数组不会比产生内建类型的数组做的更多,只需要配置足够的内存以存储10个连续的Point元素。
如果Point明确定义了默认构造函数,那么构造函数必须轮流施行于每一个元素上。
我们一般使用vec_new()函数来构造数组(这是在cfront中的方式), 对于VS等,则提供一个用来处理没有"virtual base class"的class,另一个用来处理"内含virtual base class"的class。后一个函数通常称为 vec_vnew()。函数的原型一般如下:
void *
vec_new(
void *array, // 数组的起始地址
size_t elem_size, //每一个class object大小
int elem_count, //数组中的元素个数
void (*constructor)(void *) //类的constructor函数指针
void (*destructor)(void *, char) //类的destructor函数指针
所以对上述的Point对象的初始化,对应的vec_new()的实例化如下:
vec_new( &knots, sizeof(Point), , &Point::Point, );
同理,对于对象的删除,也有类似的vec_delete()来进行操作。
void *
vec_new(
void *array, // 数组的起始地址
size_t elem_size, //每一个class object大小
int elem_count, //数组中的元素个数
void (*destructor)(void *, char) //类的destructor函数指针
5、new和delete运算符
int *pi = new int();
其实是通过两个步骤完成的,第一步通过适当的new运算符函数实例,配置所需的内存,然后将配置来的内存设定初值。
使用pi,和使用pi所指的对象,其差别在于哪一个生命已经结束了。因为即使对象不合法,但是指针所指的对象也是合法的。
new其实是通过标准的c malloc完成的,每一次对new的调用必须传回一个独一无二的指针,指向默认1byte的内存地址。
如果类对象数组没定义constructor和destructor,则不会调用vec_new。
对于delete[] p_array, 只有中括号出现时,编译器才会寻找数组的维度,否则他只会假设单独的一个object要被删除。
那么如何记录数组的元素个数呢?一个明显的方法是为vec_new()所传回的每一个内存区域块设置一个额外的word,然后把元素个数包藏在那个word之中。而包藏的数值通常称为cookie。
在原始编译器中,有两个主要函数用来存取cookie
注意,避免一个base class指针指向一个derived class object所组成的数组。即:
Point *ptr = new Point3d[];
如果一定要这样做,默认情况下只会交给施行vec_delete()函数的”被删除之指针类型的destructor“,也就是Point destructor。
所以,需要程序员如下显著的进行释放内存。
for(int ix = ; ix < elem_count; ++ ix) {
Point3d *p = &((Point3d*)ptr)[ix];
delete p;
}
6、临时性对象
对于临时性对象,许多编译器会产生临时性对象进行临时结果的存储。而临时对象的生命规则是需要的时候它应该存在,不需要了应该尽快销毁。所以就引出了临时性对象的生命规则的两个例外:
1、表达式用来初始化一个对象,只有对象的初始化完成了临时对象(用来存储表达式结果)才可以被销毁。
2、一个临时对象被绑定于一个reference,对象将残留,直到reference生命结束才可以,因为他是一个别名,否则reference没有意义了。Eg:const String &space=” ”,编译器将会产生以下代码:String temp;temp.String::String(“ ”);constString &space=temp。这个temp就是一个临时对象
临时对象的存在,是由于编译器产生的,可能会使代码的效率较低。但通过将个别成员,变量放置在register(寄存器)中、或者通过反聚合方法来提高效率
【C++对象模型】第六章 执行期语意学的更多相关文章
- 深度探索C++对象模型读书笔记-第六章执行期语意学
在函数中,编译器会帮助将析构函数(Destructor) 安插在相应的位置.对于函数中的局部对象,会将析构函数安插在对象的每一个离开点. 例如: 1: void Function(int a) { 2 ...
- 《深度探索C++对象模型》第二章 | 构造函数语意学
默认构造函数的构建操作 默认构造函数在需要的时候被编译器合成出来.这里"在需要的时候"指的是编译器需要的时候. 带有默认构造函数的成员对象 如果一个类没有任何构造函数,但是它包含一 ...
- 【C++对象模型】第二章 构造函数语意学
1.Default Constructor 当编译器需要的时候,default constructor会被合成出来,只执行编译器所需要的任务(将members适当初始化). 1.1 带有 Defau ...
- (转)iOS Wow体验 - 第六章 - 交互模型与创新的产品概念(1)
本文是<iOS Wow Factor:Apps and UX Design Techniques for iPhone and iPad>第六章译文精选,其余章节将陆续放出.上一篇:Wow ...
- Gradle 1.12用户指南翻译——第三十六章. Sonar Runner 插件
本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- 第4章 Function语意学
第4章 Function语意学 目录 第4章 Function语意学 4.1 Member的各种调用方式 Nonstatic Member Function(非静态成员函数) virtual Memb ...
- 精通Web Analytics 2.0 (8) 第六章:使用定性数据解答”为什么“的谜团
精通Web Analytics 2.0 : 用户中心科学与在线统计艺术 第六章:使用定性数据解答"为什么"的谜团 当我走进一家超市,我不希望员工会认出我或重新为我布置商店. 然而, ...
- 《Entity Framework 6 Recipes》中文翻译系列 (30) ------ 第六章 继承与建模高级应用之多对多关联
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 第六章 继承与建模高级应用 现在,你应该对实体框架中基本的建模有了一定的了解,本章 ...
- 《Entity Framework 6 Recipes》中文翻译系列 (37) ------ 第六章 继承与建模高级应用之独立关联与外键关联
翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 6-13 在基类中应用条件 问题 你想从一个已存在的模型中的实体派生一个新的实体, ...
随机推荐
- BZOJ 4736 温暖会指引我们前行 LCT+最优生成树+并查集
题目链接:http://uoj.ac/problem/274 题意概述: 没什么好概述的......概述了题意就知道怎么做了......我懒嘛 分析: 就是用lct维护最大生成树. 然后如果去UOJ上 ...
- Sublime Text 插件推荐——for web developers
楼主向高大上的: web front-end development engineer (好吧,google就是这样翻译的 ^_^)们推荐 ST 插件,在此抛砖引玉: NO.1 :Emmet (原名: ...
- 每周psp-第五周
PSP表格: 类别 任务 开始时间 结束时间 中断时间 delta时间 开会 scrum立会 10.13下午6:04 10.13下午6:34 0 30 开会 scrum立会 10.14下午6:02 1 ...
- 哈希表 STL map
计数排序时我们使用一个数组来记录出现的数字的次数,而当数据范围太大时,无法建立一个那么大地数组(而且可能空间利用率很低,太浪费),此时可以改用hash table . binary search tr ...
- lintcode-182-删除数字
182-删除数字 给出一个字符串 A, 表示一个 n 位正整数, 删除其中 k 位数字, 使得剩余的数字仍然按照原来的顺序排列产生一个新的正整数. 找到删除 k 个数字之后的最小正整数. N < ...
- LintCode-50.数组剔除元素后的乘积
数组剔除元素后的乘积 给定一个整数数组A. 定义B[i] = A[0] * ... * A[i-1] * A[i+1] * ... * A[n-1], 计算B的时候请不要使用除法. 样例 给出A=[1 ...
- erlang+thrift配合开发
I think, thrift is a tcp/ip based Client-Server architecture multi-languages supported RPC framewo ...
- 3ds Max学习日记(九)
添加了几根线条,又跟着教程细扣了一下面部细节,并把鼻子做的更细致了一些,如图: 又做了好久,按着教程抠出了眼睛和嘴,感觉自己做的模型就跟鬼似的... 做了下头发,看了下视频最后,并没教如何 ...
- 【ASP.NET Core】- 搭建MVC框架
1.使用最新版本的VS2017,并安装.NET Core2.0中相关开发工具 2.打开VS2017,点击文件-新建-项目,选择.NET Core中的ASP.NET Core Web 应用程序 ...
- 读取游标 BEGIN END
USE db_2008 --引入数据库 DECLARE ReadCursor CURSOR --声明一个游标 FOR SELECT * FROM Student OPEN ReadCursor --打 ...