const Matrix
& identity(){
static Matrix
mat_identity;
return
mat_identity;
}
local static class
object保证了如下意义:
1 mat_identity的constructor必须只能执行一次,虽然上述函数可能会被调用多次。
2 mat_identity的destructor必须只能执行一次,虽然上述函数可能会被调用多次。
3
实现方法:1> 无条件地在程序起始(startup)时构造出对象来。
2>
导入一个临时对象保护mat_identity的初始化操作。第一次处理时该对象评估为false。然后constructor会调用,然后被改为true。
对象数组
我们有下列数组定义:
Point
knots[10];
1
如果Point既没有顶一个constructor也没有定义一个destructor,我们只需配置足够的内存以存储10个连续的Point元素。
2 如果Point的确定义了一个default
constructor,所以这个constructor必须轮流实施于每个元素之上。一般这是经由一个或多个运行时库达成的。如cfront中的vec_new();
3
如果Point也定义了一个destructor,当knots的声明结束时,该destructor也必须实施于那10个元素身上。运行时库可能是vec_delete()。
default
constructor和数组
1 vec_new()取一个default
constructor的地址,激活constructor,然而这样将无法(不能允许)存取default
argument values。
2 cfront所采用的方法是产生一个内部的sub
construtor,没有参数。在其函数内调用由程序员提供的constructor,并将default
参数值明确地指定过去。
new和delete运算符
int *pi=new
int(5);
1
new调用其实有两个步骤来完成的
1> int
*pi=__new(sizeof(int)); //通过适当的new运算符实体配置内存;
2>
*pi=5;//然后设置初值。
注意:初始化操作应该在内存配置成功后才能执行。
2
delete的情况类似
delete
pi;//可能转化成一下步骤
if(pi!=0)
__delete(pi);
以constructor来配置一个class
object,情况类似。例如:
Point3d *origin=new
Point3d;//被转化为
3 Point3d *origin;
if(origin=__new(sizeof(Point3d)))
Point3d::Point3d(origin);
4 destructor的应用类似
delete origin;//被转化为
if(orgin!=0){
Point3d::~Point3d(origin);
__delete(orgin);
}
针对数组的new语意
1 int *p_array=new int[5];
vec_new()不会调用,因为它的主要功能是把default constructor施行于class
object所组成数组的每一个元素身上。不过new运算符函数会被调用。
2 //struct simple{int i1,i2;};
simple *p_aggr=new
simple_aggr[5];
vec_new也不会被调用。因为:simple并没有定义一个constructor和destructor,所以配置数组以及清除p_aggr数组的操作,只是单纯地获取内存和释放内存而已。
3 如果class定义有一个default
constructor,某些版本的vec_new()就会被调用,配置并构造class
objectes所组成的数组。
Point3d *p_array=new
Point3d[10];//通常会被编译为
Point3d *p_array;
p_array=vec_new(0,sizeof(Point3d),10,&Point3d::Point3d,&Point3d::~Point3d);
临时性对象
理论上,c++标准允许编译器厂商对是否产生临时性对象有完全的自由度。但实际上,由于市场竞争,几乎保证任何表达式如果有这种形式:
1 T c=a+b;
加法定义为:T operator+(const T &,const
T &); 或T T::operator(const T&);
实现根本不会产生一个临时对象。
注:1> 直接以拷贝构造的方式,将a+b的值放到c中。
2>
视operator的定义而定,NRV优化也可能实施起来,这将导致直接在上述c对象中求表达式结果,避免执行copy
constructor和具名对象的构造和析构。
2 然而,意义相当的赋值叙述句:
c=a+b;
不能忽略临时对象,相反,他会导致下面的结果:
//c++伪码
T temp;
temp.operator+(a,b);
c.operator=(temp);
temp.T::~T();
3 没有出现目标对象:a+b;
这时有必要产生一个临时对象,以放置运算后的结果。然后其析构有点复杂:
C++标准上这么规定:
临时性对象的被摧毁,应该是对完整表达式求值过程中的最后一个步骤。该完整表达式造成临时性对象的产生。完整表达式就是被涵括的表达式最外围那个。
4 临时性对象声明规则有两个例外:
1> 表达式被用来初始化一个object时:凡含有表达式执行结果的临时对象,应该存留到object的初始化操作完成为止。
2> 如果一个临时对象被绑定与一个reference,对象将残留,直到被初始化之reference的生命结束,或直到临时对象的声明范围结束(视哪一种情况先到而定)。