zoukankan      html  css  js  c++  java
  • 关于函数返回值的一些见解

    c++ 函数返回类型有三种: 1.返回值;  2.返回指针; 3.返回引用.
    下面介绍在函数返回的时候到底发生了什么动作。

    1.返回值类型:
    一个简单的例子:

    int get()
    {
      int n=3;
      return n;
    }

    int main()
    {
      int k=get();
    }

    先看get函数,局部变量n是产生在栈区的值,因此在函数结束时空间就会被释放,这个函数结束就底是指
    return前还是return后呢。

    答案是不一定,一般是不会立刻被释放。


    return这个动作会把n的值复制到一个临时变量q,这个临时变量充当函数的返回值,直到main函数的赋值成功后临时变量就被销毁。
    所以实际上在main函数里面 k=get(), k是获取get()函数产生的临时变量的值,而这个值的确是存在的,所以赋值成功。
    在k成功获取q的值之后,临时变量q和局部变量n可能会被销毁,由于写时复制的存在,也可能不会立刻被销毁,这是不确定的。



    2.返回指针类型:

    int *get()
    {
      int *p = new int(3);
      return p;
    }

    int main()
    {
      int *k=get();
    }

    先看get函数,局部变量p申请了一块动态内存,值为3. 在return p这里发生的动作有:
    函数会产生一个临时变量,这个变量类型是int*,我们假设为 q。
    q = p; 即q指向了p指向的地方,这里是p申请的那块动态内存
    临时变量q充当函数的返回值。


    所以在main函数里面 k = get() 实际上就是 k = q,这时候k就指向了那块动态申请的内存。
    同理临时变量q完成任务后和局部变量p的地址是无效的,但它们的值(指向的地方)仍然存在。

    所以返回一个指向动态内存的局部指针是可行的。



    错误用法:返回指向局部对象的指针。

    int *get()
    {
      int n = 3;
      return &n;
    }

    int main()
    {
      int *p = NULL;
      int *k = NULL;
      p = k = get();
      cout<<*p<<endl;
      cout<<"operation"<<endl;
      cout<<*p<<endl;
    }


    这里get函数返回的是n的地址
    在get函数返回的时候同样发生了一次复制,假设临时变量名为temp ,int *temp = &n;
    此时temp的确指向了n的地址,并作为函数的返回值返回。
    再看main函数 这里我用了一个链式复制来更好说明问题。
    先看 k = get(),即发生了 k =temp; 此时k也指向了函数n的值。
    然后p = k,p也指向了函数局部变量n的值。
    cout<<*p  神奇地发现的确输出3. 可能大家会想难道局部变量n的值还没被释放么。
    的确还是没被释放,因为n是临时变量,n的地址是被系统回收了
    但它的值还没有被别的内容写入,所以3这个值仍然存在。 之所以这里设计是涉及到一个编译器运用内存的效率,即写时复制,当需要这块内存时候直接写入省去中间释放这个步骤。
    但在第二次执行 cout<<*p<<endl; 发现不再输出3而是一个值很大的数。
    这时候说明3这个值占用的内存被重写了。 所以解释是:在第一个cout<<*p<<endl执行之后,当再运行一段时间后,系统在调用<<函数、输出结果等动作中进行了内存回收,此时该地址对应的值就被更改成无效的值了。
    所以这是一个不确定的问题,你不知道编译器什么时候会把这个临时变量n的值释放掉,所以存在安全隐患。

    返回局部引用也是如此。

    Coding Life
  • 相关阅读:
    [剑指offer] 赋值运算符重载
    [hihoCoder] 股票价格
    [LintCode] Kth Smallest Number in Sorted Matrix
    [LeetCode] Subarray Sum Equals K | 前缀和+哈希表
    [LeetCode] Add and Search Word
    [LeetCode] Implement Trie
    Tableau基础练习(三)
    Tableau基础练习(二)
    Tableau基础练习(一)
    SpringMVC用户请求下载文件
  • 原文地址:https://www.cnblogs.com/lewiskyo/p/4214604.html
Copyright © 2011-2022 走看看