[ 事情起因 ]
一天在写代码的时候,突然想到返回对象的引用好像可以提高程序的执行效率,但在调试下面代码的时候发现一运行就会报错。
而如果将上面程序中 Fun() 函数的返回类型改为 vector<char> ,即去掉引用,则程序运行正常。为什么呢?持着怀疑的态度,又测试了下面的代码:
编译之,发现 IDE 有一个 warning ,不理会它,运行之,没有报错正确地显示了运行结果。这又是怎么回事呢?
[ 分析原因 ]
其实解决这个问题的关键就是,要知道函数中声明的局部对象,它的生命周期到哪里结束。没错,函数中声明的对象只在函数内部可见。但是代码 [2] 的结果如何解释呢?出现这样的结果也许只能说明是 IDE 的问题,对于代码 [2] 有可能已经回收了内存,但是并没有修改里面的值;而在代码 [1] 中,对于 vector ,则直接回收并覆盖里面的内容。
[ 调试证明 ]
编写下面代码,运行结果说明, IDE 在函数返回以后并不会覆盖简单类型的局部对象的内存。
分别调试查看代码 [1] 中函数原型为 int Fun() 和 int& Fun() 所对应的汇编代码:
[ 得出结果 ]
当函数原型为 int Fun() 时,会将返回值 mov 到寄存器 eax 中保存,退出 Fun 后再 mov 到 a 中。
当函数原型为 int& Fun() 时,会将返回值的地址保存在 eax 中,退出 Fun 后再通过此地址读取数据到 a 中。
因此,代码 [1] 中犯了一个严重的错误, Fun() 函数返回了一个局部对象的引用。当函数 Fun() 执行完毕后,其中的局部对象所占的内存会被销毁,其中所存储的数据也就不再存在了。此时如果再使用此函数的返回值,即返回的引用类型对象的值,程序将会出现错误。
[ 结论 ]
以前在书上好像读到过,当返回一个对象的时候,如果返回的不是引用,会自动调用构造函数再创建一个临时的对象。我在这里可能存在误解,本以为返回引用可以提高效率。现在得出结论:不要返回局部对象的引用;但可以返回一个局部对象 ( 实际上是返回了一个局部对象的拷贝,实际的局部对象“可能 [1] ”已经不再存在了 ) 。
[1] “可能”的意思是,由于某些编译器的缘故,当函数执行完毕后,其中的局部对象的值可能依然存在,见代码 [2] 及 [ 调试证明 ] 。
[2] 关于此问题,我曾发布的一个帖子