c++对象模型研究6:执行期

C++的一件困难事情:不太容易从程序代码看出表达式的复杂度。

执行期语意学,即在程序执行时,编译器产生而外的指令调用,确保对象的构造,内存的释放,以及类型转换与临时对象的生成的安全进行。

 

对象的构造和析构

一般而言,我们会把对象尽可能放置在使用它的那个程序区段附近,这样做可以节省不必要的对象产生操作和摧毁操作(主要是析构)。不建议把所有的对象放在函数或某个区段的起始处。

 

 

全局对象

对于全局变量,C++会保证在调用全局变量之前,将全局变量构造出来。

而所有的全局变量都被放置在程序的数据段中(data segment),并且为没有显示指定值的变量初始化为0。

同时对于全局的类对象,在编译时期被放置于data segment中并且内容也为0.只有在程序启动时其对应的constructor才会实施。因此object需要静态初始化。

静态初始化的munch策略:

1.为每个需要静态初始化的文件产生一个_sti()函数,内含必要的constructor调用操作和inline expansions。

2.为每一个需要静态的内存释放操作的文件,产生一个_std()函数。

3.提供一个_main()函数调用所有的_sti()函数,一个_exit()函数调用所有的_std()函数

 

局部静态对象

局部静态对象的构造函数只能被施行一次,析构函数也只有一次。

所以对于局部静态对象,一个很简单的思路就是导入一个临时性对象,当第一次传入时,设置为true,之后则不再进行处理。

条件式析构也是所有编译器所必须的,而局部静态对象需以构造的相反的顺序被析构。

 

对象数组

对于以下数组定义,我们一般使用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), 10, &Point::Point, 0);


同理,对于对象的删除,也有类似的vec_delete()来进行操作。

 

 

void *
vec_new( 
    void *array,                       // 数组的起始地址
    size_t elem_size,                  //每一个class object大小
    int elem_count,                    //数组中的元素个数
    void (*destructor)(void *, char)   //类的destructor函数指针

 

 

 

 

 

new和delete运算符

int *pi = new int(5);

 

其实是通过两个步骤完成的,第一步通过适当的new运算符函数实例,配置所需的内存,然后将配置来的内存设定初值。

 

使用pi,和使用pi所指的对象,其差别在于哪一个生命已经结束了。因为即使对象不合法,但是指针所指的对象也是合法的。

new其实是通过标准的c malloc完成的,每一次对new的调用必须传回一个独一无二的指针,指向默认1byte的内存地址。

 

针对数组的new语意

如果类对象数组没定义constructor和destructor,则不会调用vec_new。

对于delete[] p_array, 只有中括号出现时,编译器才会寻找数组的维度,否则他只会假设单独的一个object要被删除。

那么如何记录数组的元素个数呢?一个明显的方法是为vec_new()所传回的每一个内存区域块设置一个额外的word,然后把元素个数包藏在那个word之中。而包藏的数值通常称为cookie。

在原始编译器中,有两个主要函数用来存取cookie


注意,避免一个base class指针指向一个derived class object所组成的数组。

 

如果一定要这样做,默认情况下只会交给施行vec_delete()函数的”被删除之指针类型的destructor“,也就是Point destructor。
所以,需要程序员如下显著的进行释放内存。

 

placement Operator new语意

 

 

临时性对象

 

临时性对象的摧毁,应该是对完整表达式求值过程中最后一个步骤。该完整表达式造成临时对象的产生。

凡持有表达式执行结果的临时对象,应该保留到object的初始化操作完成为止。

如果一个临时对象被绑定于一个reference,对象将残留,直到初始化之reference生命结束,或直到临时对象的什么范畴结束。

 

 

 

 

参考:

《深度探索C++对象模型》

http://blog.csdn.net/zone_programming/article/details/50411511

 

posted @ 2018-08-17 17:43  _raindrop  阅读(118)  评论(0编辑  收藏  举报