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

上一条款我们说了,能以pass by reference to const 尽量不用pass by value。是不是所有的都要这样呢?

这会使我们犯错:开始传递一些reference指向其实并不存在的对象,这不是一件好事。

 

考虑一个用以表现有理数的class,内含一个函数用来计算两个有理数的乘积。

classRational{

public:

       Rational(intnumerator=0

                            intdenominator=-1);

       ...

private:

       intn,d;

       friendRationaloperator*(constRational&lhs,constRational&rhs);

};

这里有版本是一个pass by value的。但是我们想能不能在函数返回时,pass by reference to const?

我们还知道,reference是一个已经存在的对象的引用。所以我们要创建一个对象,我们也知道创建一个对象可以在栈上,或堆上创建。以下版本是一个在栈上创建的。

constRational&operator*(constRational&lhs,constRational&rhs){

       Rationalresult(lhs.n*rhs.n,lhs.d*rhs.d);

       returnresult;

}

我们想在返回时,传出一个引用。这个引用指向了栈中的result。问题出来了,当函数结束时,会调用Rational的析构函数,那么result对象会被销毁。那传出去的reference是什么呢。不知道~~~~

 

如果在栈上创建,不可以的话,我们是不是可以在堆上创建?下面的版本是在堆上创建。

constRational&operator*(constRational&lhs,constRational&rhs){

       Rational*result  =newRational(lhs.n*rhs.n,lhs.d*rhs.d);

       returnresult;

}

现在的问题来了,我们依然要构造一个新对象。还不至如此,我们发现,我们new了,还没有做delete呢。那在哪里delete呢。我们没有办法~~~~~~~~~~

因此,考虑到这些,我们会想在堆和栈上都无法完成,如果我们在static上面呢?很好的想法,不过更加失败。

constRational&operator*(constRational&lhs,constRational&rhs){

       staticRationalresult;      

       result->n=lhs.n*rhs.n;   result->d=lhs.d*rhs.d

       returnresult;

}

就像所有用static对象的设计一样,这一个也立刻会造成我们对多线程的安全性的疑虑。不过那些还是显而易见的,如果想看更加深层次的,请看下面代码:

booloperator==(constRatioal&lhs,constRational&rhs){

       Rationala,b,c,d;

       ...

       if((a*b)==(c*d)){

              ...

       }else{

              ...

       }

}

你猜怎么样?(a*b)==(c*d)全部都是true。

注意在operator==作用之前,先是两个operator*起作用。还要注意每一次调用operator*都返回的是对一个static对象的引用。每一次调用的确也改变了static对象的值,但是由于是返回的reference,也就是指针。所以当两次调用后,再调用operator==时,你就会发现所指同一个static东西,且相等。

 

请记住:

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

posted @ 2012-11-15 22:40  loveyakamoz  阅读(205)  评论(0编辑  收藏  举报