程序转化语义学
主题:在对象的初始化时,编译器对用户程序的转化以及优化处理。
一,明确的初始化操作
当用户使用显示初始化的时候,编译器会进行对象重新定义,并调用对应的拷贝构造函数。例如,已知X x0; 的时候,我们使用的时候,
编译器会剖开成这样:
X x1(x0); 左边转化成右边 X x1,x2;
X x2(x0); 为编译器自行转换 x1.X::X(x0);
x2.X::X(x0);
编译器在此时如是处理的。
二,参数的初始化
当函数调用参数是对象(object)的时候,那么编译器可能会做如下两种不同的操作:
操作一:导入暂时性object。
例如:函数声明 void foo(X x0);
调用进入后,1、编译器实作一个X _temp;
2、_temp.X::X(xx)。xx为实参。
3、重新改写函数调用操作,foo(_temp);
4、修改函数声明为引用。void foo(X &x0);
这里需要记忆的是,编译器会进行这样细节的实现。
操作二:如borland C++编译器,可能会把实参直接建构到对应堆栈上。
三,返回值的初始化
返回值初始化是函数的返回值使用对象(object)做返回的情形,编译器需要做额外的处理。具体处理如下:
编译器会产生临时的引用参数,并在return之前安插此引用参数的拷贝构造。
例如:X bar() { X xx; return xx;} 会被转化为:
void bar(X & _res) //这里安插了临时引用参数
{
X xx;
xx.X::X();
_res.X::X(xx); //这里安插了临时引用的拷贝构造函数
return;
}
而相应的 bar().memfunc(); //memfunc()为X的成员函数
会被编译器转化为:
X temp0;
(bar(temp0),temp0).memfunc();
四,在使用者层面做优化
“程序员优化”观念:定义一个“计算用”的constructor
程序员不再写:
X bar(const T &y,const T &z)
{
X xx;
return xx;
}
定义另一个constructor,直接计算xx的值:
X bar(const T &y,const T &z)
{
return X(y,z);
}
编译器转化为
void
bar(x &_result)
{
_result.X::X(y,z);
return;
}
在这层面上侠侣更高,但缺乏抽象
五,在编译器层面的优化
编译器的优化和返回值初始化的编译器处理方式一样。这样的优化方式叫做NRV(Named Return Value)。
但是,不可或缺的是,我们需要一个拷贝构造函数,去开启编译器的优化。因此,在于是否一个类需要用户
自己定义拷贝构造函数,这样的问题,需要如下解释:
例如:Class Point只包含了built-in的成员。那么,默认的拷贝构造函数则是trivial的。此时,我们无需去
写一个显示的拷贝构造函数(explicit copy constructor),因为编译器会自动加上bitwise copy的行为,
这里多此一举了。但是,如果class面临了很多以传值的方式做return value的时候,我们就需要去显示地
提供一个拷贝构造,以开启编译器的NRV优化策略。