RT,effective c++ 条款21: 必须返回对象时,别妄想返回其reference。
effective一直强调要养成用const reference的好习惯,以致于我经常在不该使用reference的时候也使用它,造成不良后果,这次读书笔记就是记什么时候不该返回一个reference。 下面是书上原话:
考虑一个用以表现有理数的class,内含一个函数用来计算两个有理数的乘积:
class Rational{
public:
Rational(int num=0, int den=1);
private:
int n, d; //分子和分母
friend const Rational operator*(const Rational& lhs, const Rational& rhs);
};
这个代码是以by value形式返回计算结果(一个对象),显然代价是会调用构造函数及析构函数,增加了不少成本,但是,如果我们改成传递reference,也就是这样:
class Rational{
public:
Rational(int num=0, int den=1);
private:
int n, d; //分子和分母
friend const Rational& operator*(const Rational& lhs, const Rational& rhs);
};
假设我们在stack空间(系统自动分配内存) 里创建新对象,如下
friend const Rational& operator*( const Rational& lhs, const Rational& rhs)
{
Rational result(lhs.n*rhs.n, lhs.d*rhs.d); //警告,糟糕的代码。
return result;
}
改成这样后在编译器里运行会提示warning:返回一个局部变量或临时对象。这是为什么呢?因为这个函数返回了一个reference指向result,但是result是个local对象(本地), 而local对象在函数退出前就被销毁了! 而且返回引用也避免不了调用析构函数的成本。
又假设我们在heap(程序员自己分配内存空间)空间创建函数对象,如下:
<p><span style="font-size:18px;">friend const Rational& operator*( const Rational& lhs, const Rational& rhs)</span></p><p><span style="font-size:18px;">{</span></p><p><span style="font-size:18px;">Rational *result = new Rational(lhs.n*rhs.n, lhs.d*rhs.d); //警告,更糟的写法</span></p><p><span style="font-size:18px;">return *result;</span></p><p><span style="font-size:18px;">}</span></p>
我们还是得付出一个“构造函数调用”的代价,而且同时我们还面临了一个新的问题,谁该对着被你new出来的对象实施delete?这将很容易导致资源泄漏。
请记住:
绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向同一个local static对象而有可能同时需要多个这样的对象。