欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

条款21:必须返回对象时,别妄想返回其reference——120

程序员文章站 2022-07-12 17:51:04
...

返回reference可能指向一个销毁的local stack对象 ——120

考虑下列程序:

class Rational{
public:
    Rational(int numerator=0,
                int denominator=1);
    ...
private:
    int n,d;
    friend const Rational operator*(const Rational& lhs,
    const Rational& rhs);
};

如果定义一个local变量,就是在stack空间创建对象。将上面程序的operator* 函数写成如下:

const Rtional& operator* (const Rational& lhs, const Rational& rhs)
{
    Rational result(lhs.n*rhs.n,lhs.d*rhs.d);
    return result;
}

这样修改导致这样一个问题:首先你不免要调用Rational的构造函数,再者 result只是一个local stack变量,当调用函数结束时会被销毁,导致返回的reference指向一个空的对象。

返回reference指向一个Heap对象可能程序爱你内存泄漏——122

我们再将Rational中的operator* 函数改写成如下形式:

const Rational& operator*(const Rational& lhs, const Rational& rhs)
{
    Rational* result=new Rational(lhs.n*rhs.n,lhs.d*rhs.d);
    return *result:
}

这种改写仍然存在付出一个“构造函数调用”的代价,另者,你使用new动态分配内存,又怎么使用delete释放资源呢?这常常很困难完成。

返回reference指向static对象仍不可取——122

再次改写:

const Rational& operator* (const Rational& lhs,const Rational& rhs)
{
    static Rational result;
    result=...;
    return result;
}

这种写法像所有用上static对象的设计一样,这一个也立刻造成我们对多线程安全性的疑虑。再者,我们思考下列例子:

Rational a,b,c,d;
...
if((a*b)==(c*d)){
...
}
else{
...
}

毫不奇怪,表达式((a* b)==(c* d))总是为true。

一个“必须返回新对象”的函数的正确写法

inline const Rational operator* (const Rational& lhs,const Rational& rhs)
{
    return Rational(lhs.n*rhs.n,lhs.d*rhs.d);
}

总结——124

绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向一个local static对象而有可能同时需要多个这样的对象。条款4已经为“在单线程环境中合理返回reference指向一个local static对象”提供了一份设计实例。