执行期语义学 RunTime Semantics

if( yy == xx.getValue() ) …

X xx; Y yy;

class Y{

public:

Y();  ~Y();  bool operator == (constY& )const;

};

class X{

public:

X(); ~X(); operator Y()const; //重载转换类型操作符 必须成员不能有参数不能有返回值详细在 http://www.cppblog.com/zqsand/archive/2010/03/15/109748.html里面有介绍

X getValue();

};

看看上面的表达式怎么执行的~~~

首先等号运算符的参数确定  if(yy.operator==(xx.getValue()));

Y的== 需要一个Y型的参数,但是getvalue得到的是一个X型的,如果没有X到Y的转型方法,这个式子是错的~ 而恰好X有个类型转换符~

if(yy.operator == (xx.getValue().operator Y()))

增加的代码都是编译器默默为我们加上的~~~

注意在这个过程中,我们需要一个临时的Xobject 储存 getValue返回值 X temp1 = xx.getValue()

一个class Y object 储存 operator Y()返回值 Y temp2 = temp1.operator Y();

一个 int 放置 等号返回值  int tmp3 = yy.operator == (temp2);

最后析构函数会实施在每一个临时class object上.

所以,我们的代码变成:

{

X temp1 = xx.getValue();Y temp2 = temp1.operator Y();int tmp3 = yy.operator == (temp2);

if(tmp3)  dosth```

tmp2.Y::~Y();

tmp1.X::~X();

}

surprise~~-----------------------------------------------------------------------

6.1-对象的构造和析构

·一般来说,dtor会被放在每一个离开点(object 还存活)之前 ,所以,如果一个区段或者函数有多个离开点,那么每一个return 离开点都要插入一个dtor了。因此我们一般尽量放置object在使用它的程序区段附近,节省不必要的对象产生与摧毁操作。

·全局对象:全局对象如果有ctor或者dtor的话需要静态的初始化操作和内存释放操作。c++中全局对象放在data segment中,如果不明确指定值,内存内容为0.

但是ctor必须等到程序startup后才能实施。由于必须对一个放在datasegment 中的object初始化表达式evaluate ,所以object需要静态初始化

一种策略(cfont 的 munch)

为每一个需要静态初始化的档案产生一个  _sti()函数,内带必要的ctor调用操作或者inline expansions。 类似的产涩会给你一个std()函数调用dtor

一个_main()函数调用sti 一个 exit()函数调用_std()

然后cfont在我们的程序中安插对 _main _exit 的调用。 最后需要解决的是如何收集各个对象的sti和std。cfont使用了nm命令 , 打印出符号表格(目标文件的符号表),然后munch会搜索所有用sti或者std开头的目标函数,把他们记录到一个表格,当main和exit调用时候便利表格即可。

修改版本的方法是:system V中,coff格式的目标文件,检验可执行文件,找出有着_linknodes并且内带一个指针指向 sti 和std函数的文件,把他们都串联起来,接下来把链表头结点设置为一个全局的_head object (定义在新的 patch runtime library),这个library中有一种不同的_main _exit 他们会以head为起点,遍历链表,调用sti和std。

实际上现在的ELF格式,有init 和.fini两个section,完成静态初始化和释放操作。编译器设定的startup函数会完成平台特定的支持

virtual base class 的指针或者引用存取virtual base class subobject,是一种只有在执行期才能加以确定的操作。所以,编译器需要支持class object 的静态初始化,至少涵盖object的指针和reference。

局部静态对象

const Matrix& identity(){

    static Matrix mat_identity;

    return mat_identity;

}

mat_identity的ctor必须只执行一次,mat_identity的dtor必须只执行一次

编译器只在identity被调用的时候才构造mat_identity,这样避免如果不被调用也需要构造所有对象。同时编译器引入条件式解析~也就是如果构造了则解析之

对象数组:

Points knots[10];

如果Points没有定义ctor和dtor只要分配空间即可

如果有default ctor ,ctor必须实施于每个元素身上~这是由runtime library 完成的。 cfont中 我们使用vec_new()函数  MS和Sun提供两个函数,一个用来处理 vbs的class 一个处理内带base class 的class,后者为 vec_vnew() 函数原型基本如下

void* vec_new(void *array,size_t elem_size,int elem_count,void (*ctor)(void*),void(*dtor)(void*,char)))

array如果是0,数组由new分配与heap, vec_new(&knots,sizeof(Point),10,&Point::Point,0);

6.2 new 和 delete 运算符

int *pi  = new int(5);

执行步骤:

int* pi = __new (sizeof(int));

*pi = 5;

int *pi;

if(pi = __new(sizeof(int)))

   *pi=5;

delete pi;

if(pi!=0)

__delete (pi);

注意pi并不会自动清除为0!

CTOR

Point3d * origin=new Point3d;

if(origin = __new(sizeof(Point3d))){

try{

   origin = Point3d::Point3d(origin);   

}

calch(…){

__delete(origin);

throw;//上传exception

}

}

DTOR

delete origin;

if(origin!=0){

  Point3d::~Point3d(origin);

   __delete(origin);

}

一种library对new的设计:~~

extern void* operator new(size_t size){

if(size==0)size=1;

void *last_alloc;

while(!(last_alloc=malloc(size))){

if(_new_handler) (*_new_handler)();

else return 0;

}

return last_alloc;

}

虽然new T[0];是合法的,但是语言要求每次对new的调用必须返回一个独一无二的指针,解决该问题的传统方法是传回一个指针,指向默认为1byte的内存区块。所以size被设为1.然后这种设计允许使用者提供一个属于自己的_new_handler() 函数。

extern void operator delete (void *ptr) { if(ptr)free (char*)ptr;}

针对数组的new 语义:

int *p_array = new int[5];

这时候 vec_new()不会真正调用,因为,它的主要功能是把default ctor 实施于class object数组的每个元素身上。new运算符会被调用:

int *p_array = (int*) __new(5*sizeof(int));

如果数组的class object 有default ctor vec_new才会被调用。

Point3d *p_array = new Point3d[10];编译成:

Point3d *p_array = vec_new(0,sizeof(Point3d),10,&point3d::Point3d,&Point3d::~Point3d);

个别数组构造如果exception发生,dtor被传输给vec_new ,已经构造的object需要dtor 实施。

delete 时候,开始需要程序员指定大小,后来编译器开始不适用程序员指定的,而是只需要写delete [] ptr 即可。

如何记录数组大小呢:

一种方法在vecnew返回的内存块配置一个额外的word,大小放在其中。

如果

class Point {public:virtual ~Point (){}};

class Point3d : public Point {public:virtual ~Point3d(){}};

如果Point *ptr = new Point3d[10];

当我们delete [] ptr;时候只有 Point::~Point被掉用````

在vc里敲了代码验证确实如此~~~

实施于数组上的dtor是根据交给vec_delete()函数的被删除指针类型的dtor,也就是point的dtor,每一个元素大小也被一起传了过去。

如何避免:

避免一个base class 指针指向一个derived class 的数组。如果真的要这么写看代码吧

class point{
public:
    int p;
    point(){cout<<"point ctor"<<endl;}
    ~point(){cout<<"point dtor"<<endl;}
};
class point3d:public point{
public:
    int q;
    point3d(){cout<<"point3d ctor"<<endl;}
    ~point3d(){cout<<"point3d dtor"<<endl;}
};
int main()
{   
     point *ptr = new point3d[3];
     //delete [] ptr; 这样写是不行的

     //要这样写
     for(int i=0;i<3;i++){
         point3d * p=&((point3d*)ptr)[i]; //恢复成point3d数组指针
         delete p;
     }
}

Placement Operator New

有一个重载过的new 运算符 需要两个参数,类型为void*

Point2w *ptw = new(area) Point2w;

其中area指向内存一个区块,用来放置产生出来的Point2w object.这个预先定义好的placement operator new 实现方法: 将获得的指针arena 所指的地址传回即可

void* operator new (size_t,void* p) {return p;}

事实上,他执行的另一半工作是:把point2w 的ctor 实施于 arena所指的地址上

Point2w *ptw = (Point2w *)arena; if(ptw!=0)ptw->Point2w::Point2w();

-------

p2w->~Point2w;

p2w = new(arena)Point2w;

如果我们用

delete p2w; p2w = new(arena) Point2w;

delete会释放p2w指向的内存 由于下一指令还要用到p2w,我们应该调用dtor并保留存储空间,以便再次使用.

还有一些关于placement opeator new 的设计问题··没看明白 不记了··

6.3临时对象 :

c++对临时对象并无硬性规定,由编译器抉择。

实际上 T c = a+ b; T operator + (const T& ,const T&);

a+b可以直接构建于c上

那么根本不产生临时对象

但是,意义相当的 c=a+b;不能忽略临时对象":

T temp; temp=operator+(a,b);c.operator =(tmp);tmp.T::~T();

注意c=a+b;中,直接传递c进入operator 中,也就是不要tmp的话:由于operator函数不为其外加参数调用dtor(期望一个新鲜的内存),所以必须在其调用前调用dtor.然而转换操作会变成c.T::~T();c.T::T(a+b);copy ctor dtor  copy assignment operator 都可以自定义,所以我们用 析构和拷贝构造代替赋值一般而言是不安全的,所以需要临时对象调用operator=

所以 T c=a+b;比 c=a+b;更有效率

临时对象生命周期:

临时对象被摧毁,应该是对完整表达式求职过程的最后一个步骤,该完整表达式造成临时对象的产生

如果一个临时对象绑定在一个reference上,对象将残留,知道被初始化之reference生命结束,或者知道临时对象的声明范畴结束。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   博问   Chat2DB   管理