引用返回左值及其判断引用有效性的方法
被调函数的返回类型决定返回的是左值还是右值,当被调函数的返回类型是 引用 时,返回的是左值,其余情况下返回的是右值,被调函数返回的左值有着与其他左值类型同样的运算特性,需要特别指出的是, 我们能为返回类型是非常量引用的函数的结果赋值 ,但是需要注意的是,进行运算的前提是确保返回的引用是有效的, 返回与局部对象绑定的引用是无效的 ,因为被调函数运行结束时,局部对象的存储空间已经释放,返回与局部对象绑定的引用将会产生错误的结果,要想确保返回值的安全,我们不妨自问:引用绑定的是被调函数运行前的哪一个对象?然而,在某些时候,也是容易让人产生混淆的,譬如下面的代码,在很多人看来是错误的,但事实并非如此:
1 |
|
在 VS2013 中编译并运行以上的程序,得到了理想的结果,有人会说,不对呀,arry[index]
明明是一个局部的对象,返回一个与局部对象绑定的引用不是会产生错误的结果么?然而,arry
是一个局部对象就意味着arry[index]
也是一个局部对象吗?我们来分析一下。
main 函数中传递给 arry 的参数是 ia,即数组 ia 首元素的地址,arry[index]
实际上是对指向 ia 首元素的指针进行下标运算,相当于以下两步操作:
1 | int *p = arry; |
也就是说,arry[index]
的值就是 *(p + index)
,请注意,不是 *(p + index)
的副本,而是本身就是 *(p + index)
,这二者是同一个对象,而 *(p + index)
本质上就是 ia[index]
,即说 arry[index]
本身就是 ia[index]
而非 ia[index]
的副本,所以,arry[index]
并不是一个局部对象,它是一个在被调函数运行之前就已经存在的对象,虽然 arry 是一个局部对象,但是,由它进行下标运算而最后得到的值却不是一个局部对象。
经过以上分析,我们可以得到以下的结论:
虽然某个对象是局部对象,但是由它经过下标运算后得到的对象却并不一定是一个局部对象,应该具体问题具体分析。