我要投稿

C++中返回引用的问题

时间:2011-07-22 17:12 作者:cccbbs 阅读:1727

扫描二维码关注公众号,可以查询淘宝、京东商品优惠券
大家都知道一个常识:“千万不要返回局部对象或变量的引用和指针”。 我一直很纳闷,既然所有C++权威的书上都要求“一定不要返回局部对象或变量的引用和指针”,那为什么C++编译器不从语法上直接禁掉这种用法,让你编译通不过(在技术上应该不难实现的)。如果只是建议的话,那么“返回局部对象或变量的引用和指针”是否有用武之地呢?(从理论上来讲,我认为这种做法似乎总是错误的,原因大家都知道。) EX(1) #include using namespace std; class CComplex { public: CComplex():real(0),image(0){} CComplex(double real,double image):real(real),image(image){} CComplex& operator+(const CComplex& second) { CComplex temp(real+second.real,image+second.image); return temp; } void Print() { cout《"("《real《"+"《image《"i)"《endl; } private: double real; double image; }; int main() { CComplex a(2,4); CComplex b(1.5,3.5); CComplex c=a+b; c.Print(); return 0; } operator+返回的是临时对象的引用,为什么能正确地工作??? EX(2) #include #include using namespace std; string& f() { string s("hello"); return s; } int main() { cout《f()《endl; return 0; } 同样是对象,为什么string对象就不行,就因为string比较特殊??? EX(3) #include #include using namespace std; double& f() { double d(5.55); return d; } int main() { cout《f()《endl; return 0; } 为什么内置类型(int,float等均可)返回局部变量的引用总可以正确地工作??? 这个问题似乎以前已经有人讨论过,但一直没有定论。 不要跟我说运行正确是因为我运气好,运气不好地话就输出任意值; 我运行了N次,未见任何异常,也不要说运行上千万次才有可能出问题; 我在GCC和VS2010上都验证过了,我觉得是不是编译器做了相应的优化啊(特别是针对内置基本类型)。 有想法的兄弟望赐教,感激不尽!! int main() { CComplex a(2,4); CComplex b(1.5,3.5); CComplex c=a+b; c.Print(); return 0; } operator+返回的是临时对象的引用,为什么能正确地工作??? 答:main函数在执行之后,a,b入栈,接着a+b调用了operator+,temp也入栈,operator+执行完后,temp出栈并调用析构函数,由于出栈仅仅是移动了PC指针,而你又未写析构函数将CComplex清零,因此temp所占的那块栈空间的内存依然保持原样,只是PC指针已经不再指向它,而operator+返回的引用其实指向的是temp所占内存,然后在调用CComplex的默认拷贝构造的函数的时候,由于拷贝构造函数的输入参数也是引用,因此也指向temp那块内存,对此快内存也会按照CComplex类型来进行访问,最后c就得到了temp的内容。这里即使是写成CComplex& c=a+b;结果也是能输出temp的内容的。此时你若在此句话后面再加几个函数调用,这些函数必须要有参数或内部定义有变量,然后再c.Print(),你会发现结果完全变了。 EX(2) #include #include using namespace std; string& f() { string s("hello"); return s; } int main() { cout《f()《endl; return 0; } 同样是对象,为什么string对象就不行,就因为string比较特殊??? 答:因为s在出栈的时候其析构函数会将内存都清掉,在外面还想访问自然访问不成功了。 EX(3) #include #include using namespace std; double& f() { double d(5.55); return d; } int main() { cout《f()《endl; return 0; } 答:理解了上面两个答案,这个我就不用多说了吧。 每个人必有其背后的深刻原因,只是受限于种种因素,人们不可能都去搞明白。更多时候,并不是原因不充分,只是人们以其自己的知识背景还不足以理解。 一、为什么不禁用的问题 为什么不禁引用返回局部变量,技术上真的是不难吗?且,有足够的必要吗?请见以下例子: int *f1(int &ri) { return &ri; } int *f2() { int i=4; int *j; j=f1(i); return j; } int main() { int *p=f2(); *p=6; return 0; } p在初始化后,*p生命期是否已经结束了呢?我相信,如果这件事也得由编译器去判断,那么显然,程序员全部可以下岗了,编译器实在是太智能了,人还有必要存在吗?但现有技术真的能吗?如果能的话,要花多大开销,这个开销有必要吗?“千万不要返回局部对象或变量的引用和指针”应该是个原则性的东西,它是个典型代表,其实大原则是“不要在自动变量(不管是表达式中间结果的临时变量(如果它不能保证总优化到寄存器中)还是源程序中有明确名字的auto变量)生命期结束后还试图解引用它”。 程序设计语言课一般会说语言的可写性与可读性是对矛盾,C语言的可写性特别强,既会给比较强的人非常灵活的选择,又会让入门者走不少弯路或者半途而废。利器不是谁都能用得好,这与水平不水平没什么关系,说人的水平不足够使用C++,当然也可以站在没有学会用C++的人的立场,说C++太过于复杂,以至大多数人是学不会用不好的,但它的每个设计的确都有它的现实考虑,编程语言是很实在的东西,往往外貌冷冰冰但其为什么是这样有充足原因。 二、你的好运气 你要是明白函数调用时局部变量是如何入栈出栈的,看看反汇编的代码,并跟踪一下堆栈的变化情况,你会设计出一个让值产生变化的例子。如果这类错误后,导致被改变的值,并不是指针的值,则在这么小的程序中,系统不一定都崩溃,它不过是让部分你没照顾到的地方变了变值,却没有影响输出。 建议楼主阅读一下TCPL有关临时变量一节,看看各种条件下生成的临时变量的作用域,与给出名字的局部变量间,有何差同。 三、其他一些为什么的例子 关于C++的为什么特别多,如果你不是经验丰富且善于思考,是很难理解为什么有这么多为什么的。当然,为什么的多少,是个程度问题,有差异存在的地方就有程度问题,不同的人善用不同的东西,C++是“小众”的,但还不至于只是几个人的,毕竟TIOBE还排第3。 1.operator重载的解析顺序为什么如现在标准那样设计?是权衡了使用者的方便,和编译器的效率之间的一种平衡,它过度自由带来的是呈指数级上升的编译时开销,且该开销并不一定值得。 2.内置数组,为什么不设置下标检测?如果检测下标,定然就会在每次访问下标时,做是否越界的检验,这就带来了运行时开销。如果你的算法非常好,定然不需要检测下标,则语言假定一定要在每次访问下标时都判断,就会影响效率并失去选择的机会。如果设置N个选项,可以用来关闭或打开是否检测下标,那不应该是一种语言应该干的,各有各的侧重点。 3.C语言传数组参数为什么默认是转换成指针类型?以C语言产生那个年代的硬件条件,复制数组很奢侈,尤其函数被调用往往很频繁,算法要尽量往不复制的情况下设计,如果实在必要,非要复制,你也可以手动memcpy嘛!总之它不是默认项。C++给了用户另一种选项,即通过加上引用,而使得能够真正传整个数组,不过这都是很多年以后的事了。 4.for语句为什么有的灵活有的严格?像在Ada中的语法,便是禁止循环变量被改变,且不能设置步长值,要想达到这两个目的,便只能用其他变量再过渡,这样做是为了高度的安全。反之,C语言的for则非常灵活,也没有Ada那么多的限制,但这种灵活并不能保证用户用其写出错误逻辑的代码;VB的自由度则介于二者之间。不能因为这些语言的设计不同,而指责其中某一种语言为何不对某一语法特性做必要的限制,它真的必要吗?个案好说,但综合全局,很难评估。 四、设计者们不傻 且任何有影响力的技术,其规范,都是经过全球大量从业者多年实践后,总结整理并论证出来的,并不是一个或几个人拍拍脑袋就草率决定的,因此C++的新标准化过程要历时8年之久。Bjarne Stroustrup不傻,Herb Sutter, Stanley Lippman, Scott Meyer, Alexander Stepanov, Andrew Koenig等人也不傻,标准委员会都不是白给的,大多数细节问题早就被提出过。具体实现,要难得多,这点语法层面上的皮毛问题,都不值一提。 暂且写这么多吧。

最新评论

我要投稿 我要评论
插入url链接 添加表情
限 100000 字节
响应相关主管单位规定,关闭回帖发帖功能
[VB毕业设计] [ASP毕业设计] [JAVA毕业设计] [JSP毕业设计] [PHP毕业设计] [asp.net毕业设计] [.net毕业设计] [网络毕业设计] [Delphi毕业设计] [VC毕业设计] [VF毕业设计] [机械毕业设计] [工艺毕业设计] [模具毕业设计] [其他毕业设计]
站长联系 cccbbsnet#163.com 本站系公益性质网站,站内广告维系本站运作。欢迎赞助本站。
大学生计算机相关方向|软件编程|网络工程|web开发|数据库技术|学习资料等
本社区仅供学习计算机相关技术所使用,访客发言不得违反国家法律法规
Time now is:01-24 17:57, Gzip enabled 蜀ICP备07004838号Powered by cccbbs.net v7.5 SP3 Code © 2003-06 cccbbs
计算机毕业设计