上节我们说使用pass-by-reference-to-const比pass-by-value效率高,可是有时候为了得到正确的结果,我们必须使用pass-by-value。如果一味的使用pass-by-reference-to-const,可能会犯下一个致命的错误:开始传递一些reference指向其实并不存在的对象。
下面的例子说明了,在特定的情况下,使用pass-by-reference-to-const可能会出的错。
考率一个用以表现有理数的class,内含一个函数用来计算两个有理数的乘积。
class Rational {
public:
Rational (int numerator = 0, int denominator = 1); //构造函数 同时也是default构造函数
....
private:
int n,d;
friend const Rational operator* (const Rational& lhs, const Rational& rhs);
};
这个版本的operator*系以by value方式返回其计算结果(一个对象)。这个函数会有调用构造函数和析构函数的代价,如果使用reference就没有这些代价,现在我们分析一下,这样做可不可以。
使用reference必须之前先创建对象,函数创建对象有两个办法:在stack空间或在heap空间上。如定义一个local变量,就是在stack空间创建对象。根据这个策略的operator*如下:
const Rational& operator* (const Rational& lhs, const Rational& rhs)
{
Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
return result;
}
有两个问题:
1) 这个方式在生成result时,使用了构造函数,没有减少开销
2) 这个reference指向一个local对象result,而local在函数退出前被销毁了。所以函数返回了一个指向空的reference。这会造成严重的结果。
在heap内构造一个对象,并返回reference指向它。Heap-based对象由new创建。根据这个策略的operator*如下:
const Rational& operator* (const Rational& lhs, const Rational& rhs)
{
Rational* result = new Rational(lhs.n * rhs.n, lhs.d * rhs.d);
return *result;
}
也有有两个问题:
1) 它还是会付出一个构造函数调用代价
2) 谁该对被你new出来的对象实施delete。造成了资源泄露。
所以在这种情况下,为了得到正确的结果,必须使用pass-by-value,虽然需要付出一些代价。代码如下:
inline const Rational operator* (const Rational& lhs, const Rational& rhs)
{
return Rational result(lhs.n * rhs.n, lhs.d * rhs.d);
}
总结:
绝不要返回pointer或reference指向一个local stack对象,或返回reference指向一个heap-allocated对象,或返回pointer或reference指向一个local static对象而在可能同时需要多个这样的对象。
Effective C++读书笔记之必须返回对象时,别妄想返回其reference
最新推荐文章于 2025-03-23 18:00:00 发布