读《C++对象模型》- 执行期语意学

一、对象的构造和解构

一般而言,constructor和destructor的安插都如下:

//C++伪码
{
    Point point;
    // point.Point::Point()   //一般会被安插在这里
    ...
    // point.Point::~Point()   //一般会被安插在这里
}

如果一个作用域或函数中有一个以上的离开点,情况会稍微混乱一些。Destructor必须被放在每一个离开点之前,例如:

{
    Point point;
    // constructor 在这里
    switch( int (point.x()) ) {
        case -1:
            //...
            // destructor在这里
            return;
        case 0:
            //...
            //destructor在这里
            return;
        case 1:
            //...
            //destructor在这里
            return;
        default:
            //...
            //destructor在这里
            return;
    }
    //destructor在这里
}


在这个例子中,point的destructor必须在switch指令四个出口的return操作前被生成出来。另外也很有可能在这个作用域的结束符号之前被生成出来。因此,一般而言,我们会把object尽可能放置在使用它的那个程序区段附近,这样做可以节省不必须的对象产生操作和摧毁操作。

全局对象

C++程序中所有的global objects都被放置在程序的data segment中。如果明确指定给它一个值,object将以该值为初值,否则object所配置到的内容为0(这和C略有不同,C并不自动设定初值)。对于全局的class object,其在编译时期可以被放置于data segment中并且内容为0,但constructor一直要到程序运行时才会执行。
对于每个全局对象,编译器会为其产生一个相应的初始化函数和内存释放函数,这些函数在编译时期就通过一定的方法链接起来,并插在main函数的开始处和结束处。
sti&std

局部静态对象

对于局部静态对象,可以通过创建一个临时性的标记对象,用来判断在函数调用的时候局部静态对象是否已经被初始化,而不用在程序启动的时候将所有局部静态对象都构造出来。

二、对象数组

对于像下面的数组定义:

Point knots[10];

Point有一个default constructor,因此这个constructor必须轮流施行于knots每一个元素之上。在cfront中,使用一个命名为vec_new()的函数,产生出以class objects构造而成的数组。比较晚近的编译器,包括Borland、Microsoft和Sun,则是提供了两个函数,一个用来处理“没有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* ),
    void (*destructor)( void*, char)
}

其中constructor和destructor参数是这个class的default constructor和default destructor的函数指针,虽然constructor和destructor在程序代码是没法获取到的,但是在这里有编译器的支持,因此完全可以获取到constructor和destructor的函数指针。下面是编译器可能针对上面定义的10个Point元素所做的vec_new()调用操作:

Point knots[10];
vec_new( &knots, sizeof( Point ), 10, &Point::Point, 0);

如果Point也定义了一个destructor,当knots的生命结束时,该destructor也必须施行于这10个Point元素身上,这是经由一个类似于vec_delete()的runtime library函数完成的,其函数原型如下:

void* vec_delete(
    void *array,                                      //数组起始地址
    size_t elem_size,                                //每一个class object的大小
    int elem_count,                                  //数组中的元素数目
    void (*destructor)( void*, char)
}

如果在程序员代码中提供了一个或多个明显初始给一个由class objects组成的数组,像下面这样:

Point knots[10] = {
    Point(),
    Point(1.0, 1,0, 0.5),
    -1.0
};

那么,对于那些明显获得初值的元素,vec_new()不再有必要。对于那些尚未被初始化的元素,vec_new()的施行方式就可能被转换为:

Point knots[0];
//明确地初始化前3个元素
Point::Point( &knots[0] );
Point::Point( &knots[1], 1.0, 1.0, 0.5 );
Point::Point( &knots[2], -1.0, 0.0, 0.0 );
//以vec_new初始化后7个元素
vec_new( &knots+3, sizeof( Point ), 7, &Point::Point, 0);
This entry was posted in C/C++. Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>