花了几天时间,把《深入C++面向对象模型》看了一半的样子。确实如BBS上的同学说的那样,“帅呆了!”,绝对让你停不下来的节奏。这本书是C++经典书单里面的常客,《Effective C++》也是很多人推荐。说实话吧!我手头有一本《Effective C++》,却一直没有看完,准确地说是我没有在阅读的过程中得到很多乐趣。不是黑《Effective C++》,只是这本书的写作模式是条款式的。它的关注点在于“出什么问题?”以及“如何避免?”,而不是为什么会这样。相对来说,这本书还是比较偏工程应用,而《深入C++面向对象模型》却常常在分析编译器的一些细节,感觉更底层,更学术一些吧!
言归正传了,记一点拷贝构造函数相关的笔记。拷贝函数名为“拷贝”,却并不一定是无脑的copy。“无脑copy”的学名叫“Bitwise Copy”,就是每个bit都一起拷贝的方法。当一下四种情况出现的时候,Bitwise Copy Constructor就行了。
1、2、当class内含一个或则继承一个存在copy constructor的类;
3、当class声明了一个或多个virtual functions时;
4、当class派生自一个继承串链,其中有一个或多个virtual base classes时。
前两中情况下,编译器必须将member或base class的copy constructors调用操作安插到被合成的copy constructor中;第三种情况主要是要准确设置vptr指向的位置;第四种情况中,是因为虚基类的存在导致virtual base class的位置需要确定,所以不能简单拷贝。
函数返回值的实现和拷贝构造函数的关系也是非常密切的,下面是cfront(第一个C++编译器)的实现方法。原函数如下:
X bar()
{
X xx;
//处理 xx ...
rerurn xx;
}
转换后的伪代码:
//函数转换
//以反映出copy constructor的应用
//C++伪代码
void
bar(X& _result)
{
X xx;
//编译器所产生的default constructor调用操作
xx.X::X();
//...处理xx
//编译器所产生的copy constructor调用操作
_result.X::X(xx);
return;
}
然后编译器必须转换每一个bar()调用操作,以反映其新定义。X xx = bar();被转化为一下两个语句:
//注意,不必施行default constructor
X xx;
bar(xx);
一个显而易见的问题是程序效率。临时变量和_result之间的拷贝无疑会降低程序效率。编译器的优化方法如下:
//编译器层面的优化:
X bar()
{
X xx;
//...处理xx
return xx;
}
//编译器把其中的xx以_result取代:
void
bar(X &_result)
{
//default constructor被调用
//C++伪代码
_result.X::X();
//...直接处理_result
return;
}
这种优化有时被称为Named Return Value(NRV),在对象比较大的情况下,应该是可以节省不少时间的。