深入探索C++对象模型(6)
对象数组的构造:
对象数据的构造一般有两种方式:静态和动态
(1)静态分配
以string类为例,string a[10];就是以静态形式构造数据,这样的数组的个数是确定的不能修改的。
像这样的数组怎么进行构造和析构呢?
编译器在构造数组的时候会生成一个使用默认构造函数的数组构造函数arr_new(char *p,sizeof(string),int num,构造函数地址,析构函数地址);同样也会生成数组析构函数,形式类似。arr_del(char *p,sizeof(string),int num,析构函数地址);
若数组构造中间出现异常,该函数必须保证已构造的对象析构,然后释放内存。
如果数组对象不使用默认构造函数构造对象,必须显示构造,否则,未显示构造的对象将会使用上述函数进行默认构造。
(2)动态分配
使用new表达式进行操作,string *a=new string[10];
new表达式分为两个步骤:首先通过内存分配所用类型大小的空间,然后再该空间上调用相应的构造函数进行构造,上述语句使用默认构造函数。
delete 表达式则释放指针所指的内存(首先析构),大小按照指针类型的大小计算。与数组相对应的为delete[] a;
这样就可能造成一定错误:
当使用基类指针指向一个子类数组,则释放的时候将可能会产生错误
Base *p=new Derived[10];
delete[] p;
我们知道,new出来的数组是根据Derived对象大小*10的内存空间,而delete 则是根据指针类型的大小进行析构和释放内存的,且使用类似与静态分配时的arr_del函数进行析构释放内存,这样调用的就会是基类的析构函数和基类对象的大小。除了第一个元素,其他元素的析构都会错误的进行。
因此建议:不要使用基类指针指向一个子类数组。
上诉问题根据编译器而不同,微软的编译器可以支持使用基类指针释放子类数组,但是基于cfront的编译器g++将会出现错误,它会将指针类型的大小和析构函数传入它生成的arr_del函数进行析构释放,导致内存错误。