您的位置:首页 > Web前端

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

2012-09-10 15:24 423 查看
前一小节已经讨论过,pass by vaule的代价有时候是巨大的,pass by refrence比较方便。那么肯定也有人会立刻想到,函数返回值的时候,能不能也采用这种办法来提高程序的效率呢?
为了能够简单且说明问题,这里选择了对于内置类型返回其reference:

int& func()
{
int i=3;
return i;
}

void doNothing(int i)
{
}

int main()
{
int& k=func();

doNothing(7); //注释此行,看看有何区别

cout <<k <<endl;
return 0;
}

首先,返回局部变量的引用是不对的。因为如果你返回一个引用,引用肯定是一个对象的别名,那么你一定要先反问自己:这个引用所代表的实际值到底是谁呢?想到这里,我们就一目了然了:你返回的引用是局部变量i的别名,但是i在函数结束以后,就被释放了!所以此时的返回的是一个垃圾数字。这个程序奇怪的地方在于,如果把doNothing函数注释掉,那么程序竟然能得出正确的值,这里的奥秘在于如果调用了函数,那么栈的内容有可能发生改变,改变之后,程序就得出合理的错误值了。而当这个函数调用被注释掉以后,由于栈的内容没有改变,所以即使i已经被释放了,但是它并没有被清零,值还是3,我还是可以引用它。类似的例子还有就是返回局部变量的指针:
int* func()
{
int i=3;
int *p = &i;
return p;
}
int main()
{

int *p = func();
doNothing(1);
cout<<*p<<endl;
return 0;
}

也许,有人会想到,那么我让p指针时堆上分配的内存不就行了?
int* func()
{

int *p = new int(3);
return p;
}

但这样会则要求函数的调用者手动释放内存,否则会造成内存泄露。最致命的是,有时这种泄露是无法被释放的!

比如下面这个计算有理数的类:
class Rational
{
public:

Rational(int numerrator = 0, int denominator = 1):n(numerrator),d(denominator){}
double getVal()
{
double result = (double)n / double(d);
return result;
}
friend Rational& operator*(const Rational &lhs,const Rational &rhs);
private:
int n;//分子
int d;//分母
};

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

如果我这样调用:
Rational t1(1,1);
Rational t2(1,2);
Rational t3(1,5);

Rational t4 = t1*t2*t3;

那么t2*t3所new的指针就没办法释放了!

也许有人自作聪明的想到,让返回的引用指向一个定义域函数内部的static对象:
Rational& operator*(const Rational &lhs,const Rational &rhs)
{
static Rational result;
result = Rational(lhs.n*rhs.n,lhs.d*rhs.d);
return result;
}

假如你又定义了比较操作符:
bool operator==(const Rational &rhs)
{
return n == rhs.n && d == rhs.d;
}

但是如果你很快就会发现:if( (t1 * t2) == (t3 * t4))这样的语句总是为true。

原因在于(t1 * t2)会修改reslt的值,而(t3 * t4)又会修改result的值。总之,你始终是在做result == result 的判断,当然为true了。

总结起来就是:绝不要返回一个指向局部对象的指针或者引用,也不要返回指向分配在堆上的对象,也不要返回全局或者静态对象。返回值还是pass by value比较好。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  reference class
相关文章推荐