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

前一小节已经讨论过,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比较好。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值