对象的构造和析构
构造函数和析构函数的安插:
{
Point p;
//p.Point::Point();
...
...
//p.Point::~Point();
}
如果一个语句块(以{}
括起来的区域)或者函数中有一个以上的离开点,情况会稍微混乱一些。析构函数必须放在每一个离开点之前。
同样的道理,goto
指令也可可能需要多个析构函数调用操作。
全局对象
C++保证,一定会在main函数中第一次用到某全局对象之前,把这个全局对象构造出来,而在main函数结束之前把它摧毁掉。
这种全局对象如果有构造函数和析构函数的话,我们说它需要静态初始化和内存释放操作。
C++所有的全局对象都被放置在程序的数据段(data segment)中。如果显式指定给它一个值,此object将以该值为初值。否则object所配置到的内存内容为0。
C语言中一个全局变量只能使用一个可以编译期求值的常量表达式设定初值,但是构造函数并不是常量表达式。虽然类对象在编译器可以被放置于data segment中并且内容为0,但是构造函数一直要到程序启动(startup)时才会实施。必须对一个放置于data segment的object的初始化表达式做求值(evaluate),这正是为什么一个object需要静态初始化的原因。
- 示例
//早期cfront有一个可移植但成本破改的静态初始化。大致实现如下。
int main()
{
_main();
...
...
exit();
}
void _main()
{
__sti_xxx();//对所有global对象做static initialization操作
__sti_xxx();
...
}
void exit()
{
__std_xxx();//对所有global对象做static deallocation操作
__std_xxx();
...
}
局部静态对象(Local Static Objects)
const Matrix& Identity()
{
static Matrix mat_identity;
//...
return mat_identity;
}
虽然上述函数可能会被调用多次,但
mat_identity
的构造函数/析构函数只执行一次。
编译器的早期策略之一就是,无条件在程序startup时构造对象,即使它们所在的函数从不曾被调用过。
只在函数调用时才构造对象,是比较好的做法。现在的C++Standard已经强制要求这一点。
GPT:单个编译单元的全局对象静态初始化顺序,是按照在代码中出现的顺序进行初始化(也就是说先定义的对象先初始化)。但是在不同编译单元之间的初始化顺序却是未定义的。
CGPT:可以使用局部静态对象来实现Singleton模式,来解决跨编译单元的静态初始化顺序问题。
对象数组
声明一个class对象数组时,如果class既没有定义构造函数也没有定义析构函数,那么我们的工作不会比建立一个内建(built-in)类型的数组更多,也就是说只要配置足够内存空间来存储连续的元素即可。
如果定义了一个默认构造/析构函数,它们会轮流施行于每一个元素之上。
CRE:C++内建类型数组定义不会赋予默认值0。实测POD数组也不会赋予默认值。
new和delete运算符
int* ptr = new int(5);
new操作符的使用是由两个步骤完成的:
- 分配内存。
- 设定初值。
new运算符实际上总是以标准C的malloc()
完成,虽然并没有规定一定得这么做。相同情况,delete运算符也总是以标准Cfree()
完成。
数组的new/delete
int* arr = new int[5];
delete[] arr;
//C++2.0之前,将数组的真正大小提供给delete运算符,是程序员的责任。在2.1版本中,程序员不再需要在delete时指定数组元素个数。
//如果没有提供中括号,只有第一个元素会被析构,其他元素仍然存在。
Placement Operator new语义
有一个预定义的重载new运算符,称为placement operator new。他需要第二个参数,类型为void*
,调用方式如下。
Object* p = new (addr) Object
CRE:实际操作是两个步骤的:
- 进行指针转换。
- 将构造函数自动施行于该地址。
//C++伪码
Object * ptr = (Object*) addr;
if(ptr != 0)
{
ptr->Object::Object();
}
一般而言,placement new操作符并不支持多态。被交给new的指针,应该适当地指向一块预先分配好的内存。如果派生类比它的基类大。例如Base* ptr = new (addr) Derived;
,派生类的构造函数将会导致严重的破坏。
(END)