<<深度探索C++对象模型>>的第70页关于编译器对拷贝构造函数优化的问题再讨论~~
首先请看jinfeng_wang的帖子:
http://www.csdn.net/expert/topic/806/806937.xml?temp=.2044489
其实我看<<深度探索>>的时候也没搞清楚这个问题,在那个帖子里我胡言乱语一番,
现在想把这个问题彻底弄清楚,现在把我对书上部分内容的理解写出来,抛砖引玉,
欢迎指正.有书的朋友见书上60-75页.
问题介绍:
拷贝构造函数:以一个class object作为另一个class object的初值时调用的构造函数.
本问题就是讨论编译器调用拷贝构造函数时的策略(如何优化以提高效率),侯捷称之为"程序转化的语义学"(PROGRAM TRANSFORMATION SEMANTICS).
讨论的例子,看下面的程序段:
X bar()//显然这个函数里的bar_x的作用是返回其值,用来为函数外部的一个对象赋值.
{
X bar_x ; // 构造函数bar_x
.... //处理bar_x
return bar_x; // 析够函数 bar_x
}
void foo( )
{
//这里希望有一个copy constructor xx=bar()
X xx=bar();
// ...
// 这里调用destructor xx
}
为什么要对这个程序段优化?怎么优化?
因为语句
X xx=bar();
中下面两个地方存在可改进的地方:
1.构造bar_x的作用仅仅是返回其值,用来为函数外部的对象赋值.
2.调用bar()函数,返回时存在临时对象构造,以及拷贝构造函数的调用.
为了说明这个问题,请看bar()函数的返回值是如何从局部对象bar_x中拷贝过来的,
(Stroustrup的cfront中的双阶段转化):
1.首先加上一个额外参数,类型是class object的一个reference,这个参数将用来放置被拷贝构造而得的返回值;
2.在return指令之前安插一个copy constructor的调用操作,以便将欲传回之object的内容当作上述新增参数的初值.
这样,后一个转化操作会重新改写函数,使他不传回任何值.
这样:
X bar()
{
X bar_x ; // 构造函数bar_x
.... //处理bar_x
return bar_x; // 析够函数 bar_x
}
被转化成了:
//函数转化的c++伪码;
//以反映copy constructor的调用.
void bar (X &_result) //_result就是加上的额外参数
{X bar_x;
bar_x.X::X();//编译器所产生的default constructor的调用操作
...//处理bar_x
_result.X::X(bar_x);//编译器所产生的copy constructor调用操作
return;
}
所以语句
X xx=bar();
编译时被转换成下列两个指令句:
X xx;//注意,不实行default constructor,xx是在bar()函数中构造的
bar(xx);
看到了吧,上面说bar()中存在的两个问题 :
1.构造bar_x的作用仅仅是返回其值,用来为函数外部的对象赋值.
2.调用bar()函数,返回时存在临时对象(bar-x)构造,以及拷贝构造函数(_result)的调用.
那么怎么来改进呢?
着眼点是抑制拷贝构造函数的调用.
方法一:在使用者层面做优化,主要是某人提出了"计算用"的构造函数,
也就是构造函数内存在对成员变量除了赋值以外的操作,直接计算_result,这里不讨论.
方法二:在编译器层面作优化.编译器在bar()函数中把bar_x直接以_result取代,
所以转化前:
X bar()
{
X bar_x ; // 构造函数bar_x
.... //处理bar_x
return bar_x; // 析够函数 bar_x
}
转化后:
void bar(X &_result)
{
_result.X::X();//default constructor 被调用
....//直接对_result处理
return;
}
看到了吗?没有了bar_x对象,也没有了拷贝构造函数的调用.
这样的话,文章开头部分的程序段:
X bar()
{
X bar_x ; // 构造函数bar_x
.... //处理bar_x
return bar_x; // 析够函数 bar_x
}
void foo( )
{
//这里希望有一个copy constructor xx=bar()
X xx=bar();
// ...
// 这里调用destructor xx
}
这样,伪码如下:
void bar( X & _result) // 在编译器层遍做优化
{
//并无X xx的定义,直接将_result代入后面的表达式
... //直接处理_result
return; //65页的载使用者层面做优化
}
void foo ( )
{
X xx_result ; //这里没有调用构造函数
bar( xx_result); //在函数bar()中对xx_result构造,处理.
// 析够 xx_result
}
进入正题:你承认速度变快了吗?
但是而书上却说“在此情况下,对称性被打破了,程序运行较快,却是错误的“!
为什么?
对称性是指什么?
错在哪里呢?
{
to:jinfeng_wang(一天只需来一次),别人可以跳过,
你认为xx_result对象是在语句( X xx_result;)中就构造的,但根据<<深度探索>>p64倒数
第6行特意指出xx_result不是这里构造的而是在bar()函数体里构造的,你可以看上面的伪码,摘自p64.
}
我开始理解对称性是指构造函数与析构函数个数要对称,现在根据上面的分析可以看出,
这里的"对称性"显然指构造函数与析构函数的位置不对称.
因为
xx_result的构造函数在bar()中调用.
而析构函数在foo()的末尾调用.
(请看上面的伪码).