首页 > 代码库 > 条款21:必须返回对象时,别妄想返回其reference

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

条款21:必须返回对象时,别妄想返回其reference
引用只是对象的一种别名当使用引用的时候,请确认他的另一个身份在哪?
class Rational
{
public:
	Rational(int x, int y) : m_x(x), m_y(y){}

	//返回const是属于类型保护,friend修饰,以后条款详说
	friend const Rational operator + (const Rational &lhs, const Rational &rhs)  
	{
		Rational temp(lhs.m_x + rhs.m_x, lhs.m_y + rhs.m_y); //还有更好的做法
		return temp;
	}
private:
	int m_x;
	int m_y;
};
        实现+号重载,我们采用return value,根据前面条款,返回value会调用一系列拷贝构造函数,析构函数的成本,于是我们修改为return reference
	friend const Rational& operator + (const Rational &lhs, const Rational &rhs)  
	{
		Rational temp(lhs.m_x + rhs.m_x, lhs.m_y + rhs.m_y); //还有更好的做法
		return temp;
	}
       +号返回的引用对象在哪?我们看到在函数中创建一个临时对象temp,这个是属于栈空间对象,跳出函数作用域被回收,则引用的对象已经不存在了,程序会出现不可意料的行为。
        上面我们提到函数实现还有一个更好的做法
	friend const Rational operator + (const Rational &lhs, const Rational &rhs)  
	{
		return Rational(lhs.m_x + rhs.m_x, lhs.m_y + rhs.m_y); //标准做法
	}
       分析下:第一种做法是创建临时对象,调用构造函数初始化,返回时调用拷贝构造函数初始化存放返回值的外部变量,最后调用析构函数。而第二种是编译器直接创建临时对象并初始化外部变量,省去调用拷贝构造函数和析构函数。
       如果考虑到在heap里面创建对象不会容易被回收,并使用reference返回,那么这个代价更大。

	friend const Rational& operator + (const Rational &lhs, const Rational &rhs)  
	{
		return *(new Rational(lhs.m_x + rhs.m_x, lhs.m_y + rhs.m_y));
	}
看下面调用
	Rational x(1,2), y(3, 4), z(5, 6);
	Rational r = x + y + z;
      调用了两次operator +,两次new调用分配内存,但没有合理的方法delete内存,因为没有合理的方法取得返回reference的那个指针,导致内存泄露。
     如果还是希望让函数返回reference而通过定义一个local-static对象替代heap对象,那么这个代价不比heap方法的小。

	friend const Rational& operator + (const Rational &lhs, const Rational &rhs)  
	{
		static Rational sRational(lhs.m_x + rhs.m_x, lhs.m_y + rhs.m_y);
		return sRational;
	}
使用了静态变量在多线程安全性中存在隐患这一个问题暂且不说,还有一个是调用判断相等时出现逻辑错误
调用==判断
	Rational x(1,2), y(3, 4), z(5, 6), w(7, 8);

	if ((x + y) == (z + w)) {
		cout<<"equal\n";
	}
       因为+号返回引用,而引用执行的对象时static,两次的+号返回reference其实是指向同一个对象,那==值判断永远相等。
记住
       绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向一个local static对象而有可能同时需要多个这样的对象.条款4已经为"在单线程环境中合理返回reference指向一个local static对象"提供一份设计实例.