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

条款21:必须返回对象时,别妄想返回其reference
    (Don't try to return a reference when you must return an object.)

内容:
    前面一款我们提到了pass-by-value方式参数传递的效率带来的一系列可能引发的问题,你可能对pass-by-
reference-const的参数传递方式特别的'青睐',而现在我们需要在在一次函数调用中要返回一个对象,问题是我
们将以何种方式返回这个对象,你这个时候迫不及待的告诉我你的方案:直接返回该对象的reference.嗯,我们先
用你的方案去解决下面这个问题,假设现在我们需要处理有理数Rational类:
    class Rational{
    public:
        Rational(int numerator=0,int denominator=1);
        ...
    private:
        int numerator_,denominator_;
        friend Rational& operator* (const Rational& lhs,const Rational& rhs);
    };
    ...
    Rational& operator*(const Rational& lhs,const Rational& rhs){
        Rational result( lhs.numerator_ * rhs.numerator_, lhs.denominator_ * rhs.denominator_ );
        return result;
    }
    哦吼,问题来了,你返回的对象result是一个local对象,此对象在函数退出时候自动调用析构函数来销毁自己,
不存在了,你现在却在返回一个不存在对象的引用,你就会陷入"未定义"的危地.你这时立刻就想到了一个解决方案:
在heap上产生该对象不就问题解决了嘛,因为堆上的对象不会自动销毁自己(除非你手工调用delete操作).ok,那么
我们再来改一下代码看这种方案是否可行:
    Rational& operator*(const Rational& lhs,const Rational& rhs){
        Rational* result=new Rational(lhs.numerator_ * rhs.numerator_,
                                    rhs.denominator_ * rhs.denominator_);
        return *result;
    }
    这样实现貌似很合理,其实这里还是存在一个问题:你new出来的对象何时被delete掉,谁负责执行delete操作.
如果客户在使用这个类的时候写出如下代码:
    Rational x,y,z,w;
    w=x*y*z; //operator*(x,operator*(y,z));
    这个时候operator*(y,z)对象的reference(其实就是指针)就会丢失,你就无法执行delete操作,那么这里明显就
存在了内存泄露的风险.晕,这样也不行,这时聪明的你灵感又来了:用static修饰local对象.你这样想的理由可能是下
面两点:(1)static对象常驻内存,一旦对象被创建,你就不能随意去销毁它,除非程序结束;(2)每次调用该函数只是修
改该对象的值,该对象始终只会存在一个.听起来想法很不错,我们依然还是先修改代码,看这方案是否可行?
    Rational& operator*(const Rational& lhs,const Rational& rhs){
        static Rational result;
        ...
        result=...;
        return result;
    }
    而现在我们的客户却一不小心写下了这样的代码:
    Rational a(2,3);
    Rational b(4,5);
    Rational c(4,7);
    Rational d(7,8);
    if( (a*b) == (c*d)){
        ...
    }
    晕,问题又来了:a*b与c*d返回的对象引用都是引用的同一个static对象,那么这样的比较就显的没有意义了,因为
结果一直都是true,哎呀,方案又'破产'了,问题没解决,心情很郁闷?别急,其实这里的解决方案很简单:我们只需要直接
返回该对象就行了,我们先看一下最新的代码:
    const Rational operator*(const Rational& lhs,const Rational& rhs){           
        return result(lhs.numerator_ * rhs.numerator_,lhs.denominator_ * rhs.denominator_);       
    }
    呵呵,现在你看看所有问题不是都解决了嘛!当然,你需要承受operator*返回值的构造成本和析构成本,然而长远来
看那只是为了获得正确行为而付出的一个小小代价,好了,该条款至此就over了!
   
    请记住:
    ◆ 绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或
返回pointer或reference指向一个local static对象而有可能同时需要多个这样的对象.条款4已经为"在单线程环境中合理
返回reference指向一个local static对象"提供一份设计实例.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值