对象数组的构造与析构
假如我们有如下的数组定义:
Point knots[10];
需要完成什么东西呢?如果Point既没有定义一个constructor也没有定义一个destructor,那么我们的工作不会比建立一个"内建类型所组成的数组"更多,也就是说,我们只需要配置足够的内存以存储10个连续的Point元素
然而Point的确定义了一个默认析构函数,所以这个析构函数必须轮流施行于每一个元素之上。一般而言这是经由一个或者多个runtime library函数达成。在cfront中使用了一个叫做vec_new()
函数,生成以class objects构造而成的数组。而一些新出的编译器一般提供两个函数,一个用来处理"没有虚基类"的类,另一个用来处理"内带虚基类"的类。后一个函数通常称为vec_nnew()
void * vec_new(
void *array, // 数组起始地址
size_t elem_size, // 每一个class object的大小
int elem_count, // 数组中的元素数目
void (*constructor)(void *),
void (*destructor)(void *, char)
)
其中:
-
constructor和destructor参数是这个类的默认构造函数和默认析构函数的函数指针。
-
参数array值:
- 具名数组(本例为knots)的地址
- 或者是0。如果是0,那么数组将经由应用程序的new运算符,被动态配置于heap中。
- Sum把”由类对象所组成的具名数组“和"动态配置来的数组"的处理操作分为两个library函数:__vertor_new2和__vector_con,它们各自拥有一个virtual base class函数实体
-
参数elem_count表示数组中的元素数目
- 在vec_new()中,constructor施行于elem_count个元素之上
对于支持exception handling的编译器而言,destructor的提供是必要的。下面是编译器可能针对10个Point元素所做的vec_new()调用操作:
Point knots[10];
vec_new(&knots, sizeof(Point ), 10, &Point::Point, 0);
如果Point也定义了一个析构函数,当knots的声明结束时,该destructor也必须施行于那10个Point元素上。通过vec_delete()
(或者是vec_vdelete()
— 如果类具有虚基类的话)的runtime library函数完成:
void * vec_delete(
void *array, //数组的起始地址
size_t elem_size, // 每一个class object的大小
int elem_count, //数组中的元素数目
void (*destructor)(void *, char)
)
有些编译器会另外增加一些参数,用来传递其他数值,以便能够有条件的导引vec_delete()
的逻辑。在vec_delete中,析构函数被施行于elem_count个元上。
如果定义了一个或者多个初值给一个由类对象组成的数组,比如:
Point knots[10] = {
Point(),
Point(1.0, 1.0, 0.5),
-1.0
};
对于那些明显获得初值的元素,vec_new()不再有必要。对于那些尚未被初始化的元素,vec_new()的施行方式就像面对"由类元素组成的数组,而该数组没有显示初始化列表"一样。也就是说,上面会被转换成:
Point knots[10];
// 明确的初始化前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(&knots + 3, sizeof(Point ), 7, &Point::Point, 0);