引用返回左值及其判断引用有效性的方法

被调函数的返回类型决定返回的是左值还是右值,当被调函数的返回类型是 引用 时,返回的是左值,其余情况下返回的是右值,被调函数返回的左值有着与其他左值类型同样的运算特性,需要特别指出的是, 我们能为返回类型是非常量引用的函数的结果赋值 ,但是需要注意的是,进行运算的前提是确保返回的引用是有效的, 返回与局部对象绑定的引用是无效的 ,因为被调函数运行结束时,局部对象的存储空间已经释放,返回与局部对象绑定的引用将会产生错误的结果,要想确保返回值的安全,我们不妨自问:引用绑定的是被调函数运行前的哪一个对象?然而,在某些时候,也是容易让人产生混淆的,譬如下面的代码,在很多人看来是错误的,但事实并非如此:


#include <iostream>
#include <cstddef>
#include <iterator>
using std::cout;
using std::endl;
using std::begin;
using std::end;
 
int &get(int *arry, size_t index)
{
    return arry[index];
}
 
int main()
{
    int ia[10] = { 2, 4, 6, 8, 1, 3, 5, 7, 9, 10 };
    for (size_t i = 0; i != 10; ++i)   // 将 ia 元素的值改为对应的下标
        get(ia, i) = i;
 
    for (auto ibeg = begin(ia), iend = end(ia); ibeg != iend; ++ibeg)
        cout << *ibeg << " ";
    cout << endl;
 
    return 0;
}   

在 VS2013 中编译并运行以上的程序,得到了理想的结果,有人会说,不对呀,arry[index] 明明是一个局部的对象,返回一个与局部对象绑定的引用不是会产生错误的结果么?然而,arry 是一个局部对象就意味着arry[index] 也是一个局部对象吗?我们来分析一下。

main 函数中传递给 arry 的参数是 ia,即数组 ia 首元素的地址, arry[index] 实际上是对指向 ia 首元素的指针进行下标运算,相当于以下两步操作:


int *p = arry;
*(p + index);  

也就是说,arry[index] 的值就是 *(p + index) ,请注意,不是 *(p + index) 的副本,而是本身就是 *(p + index) ,这二者是同一个对象,而 *(p + index) 本质上就是 ia[index],即说 arry[index] 本身就是ia[index] 而非 ia[index] 的副本,所以,arry[index] 并不是一个局部对象,它是一个在被调函数运行之前就已经存在的对象,虽然 arry 是一个局部对象,但是,由它进行下标运算而最后得到的值却不是一个局部对象。

经过以上分析,我们可以得到以下的结论:

虽然某个对象是局部对象,但是由它经过下标运算后得到的对象却并不一定是一个局部对象,应该具体问题具体分析。
————————————————
版权声明:本文为CSDN博主「abnerwang_smile」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/abnerwang2014/article/details/26720455

上一篇:Linux学习笔记总结


下一篇:Myeclipse导入不了自己建的包