条款21:必须返回对象时,别妄想返回其reference。
来源:互联网 发布:淘宝卖蜂蜜选什么类目 编辑:程序博客网 时间:2024/04/29 05:36
前一小节已经讨论过,pass by vaule的代价有时候是巨大的,pass by refrence比较方便。那么肯定也有人会立刻想到,函数返回值的时候,能不能也采用这种办法来提高程序的效率呢?
首先,返回局部变量的引用是不对的。因为如果你返回一个引用,引用肯定是一个对象的别名,那么你一定要先反问自己:这个引用所代表的实际值到底是谁呢?想到这里,我们就一目了然了:你返回的引用是局部变量i的别名,但是i在函数结束以后,就被释放了!所以此时的返回的是一个垃圾数字。这个程序奇怪的地方在于,如果把doNothing函数注释掉,那么程序竟然能得出正确的值,这里的奥秘在于如果调用了函数,那么栈的内容有可能发生改变,改变之后,程序就得出合理的错误值了。而当这个函数调用被注释掉以后,由于栈的内容没有改变,所以即使i已经被释放了,但是它并没有被清零,值还是3,我还是可以引用它。类似的例子还有就是返回局部变量的指针:
也许,有人会想到,那么我让p指针时堆上分配的内存不就行了?
但这样会则要求函数的调用者手动释放内存,否则会造成内存泄露。最致命的是,有时这种泄露是无法被释放的!
比如下面这个计算有理数的类:
如果我这样调用:
那么t2*t3所new的指针就没办法释放了!
也许有人自作聪明的想到,让返回的引用指向一个定义域函数内部的static对象:
假如你又定义了比较操作符:
但是如果你很快就会发现:if( (t1 * t2) == (t3 * t4))这样的语句总是为true。
原因在于(t1 * t2)会修改reslt的值,而(t3 * t4)又会修改result的值。总之,你始终是在做result == result 的判断,当然为true了。
总结起来就是:绝不要返回一个指向局部对象的指针或者引用,也不要返回指向分配在堆上的对象,也不要返回全局或者静态对象。返回值还是pass by value比较好。
为了能够简单且说明问题,这里选择了对于内置类型返回其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比较好。
- 条款21:必须返回对象时,别妄想返回其reference
- 条款21:必须返回对象时,别妄想返回其reference
- 条款21:必须返回对象时,别妄想返回其reference
- 条款21:必须返回对象时,别妄想返回其reference。
- 《Effective C++》学习笔记条款21 必须返回对象时,别妄想返回其reference
- Effective C++——》 条款21:必须返回对象时,别妄想返回其reference。
- 条款21:必须返回对象时,别妄想返回其reference
- 条款21:必须返回对象时,别妄想返回其reference
- Effective C++:条款21:必须返回对象时别妄想返回其reference
- Effective C++ 读书笔记 条款21:必须返回对象时,别妄想返回其reference
- 条款21、必须返回对象时,别妄想返回其reference
- effective c++ 条款21: 必须返回对象时,别妄想返回其reference
- 条款21 必须返回对象时,别妄想返回其reference
- 《Effect C++》学习------条款21:当必须返回对象时,别妄想返回其reference
- 读书笔记《Effective C++》条款21:必须返回对象时,别妄想返回其reference
- 条款21:必须返回对象时,别妄想返回其reference
- 条款21:必须返回对象时,别妄想返回其reference
- item21: 必须返回对象时,别妄想返回其reference
- oracle存储过程中无法调不同用户表的问题
- Inside Qt Series (八):Meta Object Class overview
- HDU 2055
- java数据库
- HDU 1150
- 条款21:必须返回对象时,别妄想返回其reference。
- 在C语言有一定基础之后,怎么样能够更快的成长?
- Inside Qt Series (九):QMetaObject class data members
- mysql游标实例
- Inside Qt Series (十):connect,幕后的故事
- Spring的核心机制依赖注入讲解
- 《深入java虚拟机》学习笔记(第十九章 方法的调用和返回)
- 再谈PN学习
- Inside Qt Series (十一):emit,幕后的故事