首页 > 代码库 > [021]必须返回对象时,别妄想返回其reference

[021]必须返回对象时,别妄想返回其reference

引言

在条目20中,我们知道了值传递和引用传递的效率问题,因此在设计程序时,我们可能就尽可能来返回引用而不是值。

可是,可能会犯下面的一些错误:传递一些引用指向其实并不存在的对象。

第一节:返回临时变量的引用

假如我们有以下的例子,先看值传递

 1 class A { 2 public: 3     A(int n = 0, int d = 1):n(n),d(d) {} 4 private: 5     int n,d; 6     friend const A operator* (const A& l, const A& r); 7 };

在operator*系以值传递的方式返回了一个计算结果,联系到条款20,我们自然会想到,那么用引用传递试试。

因为函数返回的是A对象,所以函数创建新对象的方式有2:

1.在stack空间创建

1 const A& operator* (const A& l, const A& r) {2     A result(l.n * r.n, l.d * r.d);3     return result;4 }

这样我们避免值传递的调用构造和析构函数,可是result是个临时变量,在函数推出前就被销毁了。任何对这个函数的调用都会是无意义的行为。

2.在heap空间创建

1 const A& operator* (const A& l, const A& r) {2     A* result = new A(l.n * r.n, l.d * r.d);3     return *result;4 }

这样解决了上面临时变量的问题。可是,这个new出来的对象什么时候被释放呢?

就算我们调用A的时候很谨慎,但还是避免不了出错,比如

1 A w,x,y,z;2 w = x * y * z;     // 实际与operator*(operator*(x, y), z)相同

这里同一个语句例调用了两次operator*,因此两次使用new,也就需要两次delete,但却没有合理的办法让operator*使用者进行那些delete调用。这就会导致资源泄露。

经过上面两种方法都不行,可能你还会想到这种方法:我声明一个static对象不行么?

比如:

1 const A& operator* (const A& l, const A& r) {2     static A result;3     result = .....4     return result;5 }

看上去完美的解决了这个问题,那么我们这样使用的时候呢?

1 bool operator == (const A& l, const A& r);2 A a,b,c,d;3 if ((a*b) == (c*d)) {4 ....5 }

结果就会出现:(a*b) == (c*d)总是为true,无论a,b,c,d是什么!

将(a*b) == (c*d)拆开来理解,我们就可以知道为什么了。

operator == (operator*(a, b), operator(c*d));

因为到最后位置,都会返回static对象的现值,也就不怪乎为什么返回true了。

 

◆总结

1.绝不要返回pointer或者referenc指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向一个local static对象。

[021]必须返回对象时,别妄想返回其reference