绝对不要返回point或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回point或reference指向一个local static对象而有可能同时需要多个这样的对象。
我们来考虑一个有理数的类以及为它定义一个有理数想乘的友元:
class Rational{ public: Rational(int numerator = 0, int denominator = 1); private: int n, d; friend const Rational operator*(const Rational& lhs, const Rational& rhs); };
现在我们来设计这个友元函数,它的功能是返回两个Rational对象的乘积,我们有3种方案:
// 方案一 const Rational& operator*(const Rational& lhs, const Rational&rhs) { Rational result(lhs.n*rhs.n, lhs.d*rhs.d); return result; }
这个函数返回了result的引用,但是result是一个local对象,调用函数结束时,该对象会被销毁,而它的引用也就毫无意义指向了未定义的对象。
// 方案二 const Rational& operator*(const Rational& lhs, const Rational& rhs) { Rational* result=new Rational(lhs.n*rhs.n, lhs.d*rhs.d); return *result; }
方案中result并不是一个local对象,而是一个从heap中动态分配得到的对象的指针,那么这样的问题是谁来负责delete这个指针呢,假如有这样的表达式:
Rational w, x, y, z; w = x*y*z;
这面的表达式其实调用了两次operator*操作,也就是创建了两次动态内存区域,但是没有办法取得它们的指针。
// 方案三 const Rational& operator*(const Rational& lhs, const Rational& rhs) { static Rational result; result = Rational(lhs.n*rhs.n, lhs.d*rhs.d); return result; }
这次是通过static对象使得result脱离函数后依然存在,但是就像所有的static对象设计一样,这一个也立刻造成我们对多线程安全性的疑虑。而且如果有下面的