在之前的博客中有专门一章讲述在C++中为什么尽量在传参时用pass-by-reference取代pass-by-value,其主要目的是为了节省构造函数和析构函数的成本,但这不能完全的取代,假如有下面的一个类:
1 class Rational
2 {
3 public:
4 Rational(int numerator = 0, int denominator = 1);
5 private:
6 int n, d;
7 };
现在为此类添加成员函数operator*,不妨先找找以下的代码有什么问题:
const Rational& operator*(Rational& a, Rational& b)
{
Rational result(a.n*b.n, a.d*b.d);
return result;
}
这段代码有两个问题需要注意:第一 在函数内部定义了一个local对象,然后返回它的地址,而我们应该指导local对象会在退出函数时被销毁,所以如果用户使用这个reference指向的对象会出现”未定义错误“;第二 result的创建还是逃避不了构造函数调用的成本。
也许有人提出利用堆来取代栈存放这个对象,这样一来,对象就不会在函数调用结束时退出,即将代码改造如下:
const Rational& operator*(Rational& a, Rational& b)
{
Rational *result = new Rational(a.n*b.n, a.d*b.d);
return *result;
}
即使如此改造,依然改变不了需要调用构造函数的成本。此外,它无法对new出的那块内存进行释放,因为用户无法获取operator*返回的reference指向表示的对象背后指向它的指针。
或者还有人提出既然stack和heap存放对象分别会带来未定义和无法释放内存的问题,那就用local-static对象,这样一来就不需要构造函数的成本,函数返回的reference指向一个定义于函数内部的存放在静态区域的对象,程序结束前不会被销毁,也不需要释放内存,因而可以解决上面的几个问题,但是它存在多线程安全性的问题。另外,考虑下面的代码,看看是否有问题:
1 const Rational& operator*(const Rational& a, const Rational& b)
2 {
3 static Rational result;
4 result.n = a.n*b.n;
5 result.d = a.d*b.d;
6
7 return result;
8 }
9
10
11 Rational a(2,1);
12 Rational b(2,3);
13 Rational c(3,4);
14
15 if(a*b == c*a)
16 {
17 cout<<"equal"<<endl;
18 }
上面的代码的问题是15行的if语句总是真,所以17行的语句总会执行,原因是ab返回的reference指向的是一个static对象,当执行ca后,虽然这个static对象发生了变化,但ab返回的reference依旧指向这个static对象,也就是两次执行operator返回的reference其实一直指向同块区域中的对象,因而当然是相等的。
可以看到,试图返回一个reference参数在这里并不合适,这时就只好返回一个value对象,也因而必须付出调用构造函数和析构函数的成本,但这时保证程序运行结果正确是关键的,即代码修改如下:
1 friend const Rational operator*(const Rational& a, const Rational& b)
2 {
3 Rational result(a.n*b.n, a.d*b.d);
4 return result;
5 }
事实上,我在VS2010中运行下段代码时并没有出现预期中的”未定义错误“,我求助于一个C++群,结果有人指出编译器优化的可能性,也许真的是这个原因,只能说编译器能做的事越来越多,考虑的也越来越全。
1 const Rational& operator*(Rational& a, Rational& b)
2 {
3 Rational result(a.n*b.n, a.d*b.d);
4 return result;
5 }
6
7 Rational a(2,1);
8 Rational b(2,3);
9
10 const Rational c = a*b;
11 const Rational d = c*b;
以上整理自Effective C++ 中文版第三版。
原文链接: https://www.cnblogs.com/sophia-yun/archive/2013/05/18/3086228.html
欢迎关注
微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍
原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/88990
非原创文章文中已经注明原地址,如有侵权,联系删除
关注公众号【高性能架构探索】,第一时间获取最新文章
转载文章受原作者版权保护。转载请注明原作者出处!