Effective C++条款21:必须返回对象时,别妄想返回其引用
之前条款20说到,pass-by-reference比pass-by-value通常高效的多.
可能这会导致你,什么时候都用按引用来替代传值.
但是注意:所谓的引用只是给一个对象取了另一个别名, 当你见到引用时,一定要问一下自己,它另外一个名字是什么?因为引用一定是一个对象的另一个名称。
考虑有以下的类:
class Time
{
private:
int hours;
int minutes;
public:
public:
Time();
Time(int h, int m = 0);
friend Time operator+(const Time & t, const Time & t1);
friend Time operator-(const Time & t, const Time & t1);
friend Time operator*(const Time & t, double n);
};
这个版本以by value方式返回一个计算结果,想想如果我们可以改成传递reference,就不需要付出代价,比如构造和析构成本。
如果operator*要返回一个reference,它必须自己创建那个Time对象,前面说过了所谓的引用只是给一个对象取了另一个别名。
按照这个规则,我们尝试这样写:
const Time& operator*(const Time & t, double n)
{
long totalminutes = t.hours * n * 60 + t.minutes * n;
Time result(totalminutes / 60,totalminutes % 60);
return result;
}
这样的写法造成的问题是:result是一个局部对象,局部对象在函数退出前被销毁了,因此这个版本返回了一个无用的引用,它指向的对象已经被销毁了.调用这个引用,将会导致不可预料的错误.
或许我们可以考虑在堆内构造一个函数,可以这样写:
const Time& operator*(const Time & t, double n)
{
long totalminutes = t.hours * n * 60 + t.minutes * n;
Time result = new Time(totalminutes / 60,totalminutes % 60);
return result;
}
但是这样还是付出一个构造函数调用代价,而且还有一个问题:谁该对被new出来的对象实施delete?
即使你delete了,考虑以下代码:
Time W,x,y,z;
W = x * y * z;
这里同一个语句调用了两次operator*
,使用了两次new
,也就需要两次delete
.但是我们没有合理的办法让operator*
使用者进行那些delete
调用,因为没有合理的办法取得operator*
返回的引用背后隐藏的那个指针
或许我们还可以通过静态对象来,考虑以下代码:
const Time& operator*(const Time & t, double n)
{
static Time result;
result = ...;
return result;
}
问题在于:这可能会造成多线程安全性问题,此外考虑以下代码:
bool operator==(const Time& lhs, const Time&rhs);
Time a,b,c,d;
...
if((a*b)==(c*d))
{
...
}
else
{
...
}
这将导致(a*b)==(c*d)
永远为true,无论a,b,c,d的值是什么.
将代码重写为等价的函数形式:
if(operator==(operator*(a,b), operator*(c,d)))
在operator==
被调用前,两个operator*
已经起了作用。
每一个都返回引用指向operator*
内部定义的静态Time对象。因此operator==被要求将"operator内的static Time对象值"拿来和"operator内的static Time对象值比较",所有比较结果相等(两次operator*调用的确各自改变了静态Time对象值,但是a b c d都引用了同一个静态对象,因此都相等.).
所以一个最好的写法就是,就让那个函数返回一个新对象:
Time operator*(const Time & t, double n)
{
Time result;
long totalminutes = t.hours * n * 60 + t.minutes * n;
result.hours = totalminutes / 60;
result.minutes = totalminutes % 60;
return result;
}
总结:
不要返回指针或引用指向一个局部栈对象,或返回引用指向一个堆分配的对象,或返回指针或引用指向一个静态对象而有可能同时需要多个这样的对象。
上一篇: 条款21:必须返回对象时,别妄想返回其reference——120
下一篇: mysql必知必会
推荐阅读
-
条款21:必须返回对象时,别勉强返回其reference
-
Effective C++条款21:必须返回对象时,别妄想返回其reference
-
条款21(二):必须返回对象时,别妄想返回其reference
-
条款21(一):必须返回对象时,别妄想返回其reference
-
条款21:必须返回对象时,别妄想返回其reference——120
-
Effective C++条款21:必须返回对象时,别妄想返回其引用
-
条款21:必须返回对象时,别妄想返回其reference
-
读书笔记《Effective C++》条款21:必须返回对象时,别妄想返回其reference
-
Effective C++ 详解条款21:必须返回对象时,别返回其reference
-
读书笔记《Effective c++》 条款21 必须返回对象时,别妄想返回其reference