当前位置: 首页 > news >正文

关于函数返回值的一些见解

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的值释放掉,所以存在安全隐患。

返回局部引用也是如此。

转载于:https://www.cnblogs.com/lewiskyo/p/4214604.html

相关文章:

  • Git 的是使用入门
  • Hover States - 有趣的用户界面及交互设计
  • JavaScript Array创建数组
  • C缺陷与陷阱----读书笔记---第一章
  • 利用firefox调试安卓手机端web
  • 笔记:Java面向对象编程 第10章 类的生命周期
  • 锁定应用,解锁应用,锁卡,解卡,更改密码指令
  • Matlab的部分文件操作
  • 如何管理?
  • 系统时钟和硬件时钟同步
  • (转)总结使用Unity 3D优化游戏运行性能的经验
  • zblog2.0博客建站视频教程
  • Product Google的十大设计原则
  • 如何修复U盘提示被写保护的问题
  • 浅谈Docker(一)
  • 网络传输文件的问题
  • Facebook AccountKit 接入的坑点
  • hadoop入门学习教程--DKHadoop完整安装步骤
  • iOS小技巧之UIImagePickerController实现头像选择
  • JS进阶 - JS 、JS-Web-API与DOM、BOM
  • MySQL几个简单SQL的优化
  • oldjun 检测网站的经验
  • react-native 安卓真机环境搭建
  • 短视频宝贝=慢?阿里巴巴工程师这样秒开短视频
  • 前端代码风格自动化系列(二)之Commitlint
  • 吐槽Javascript系列二:数组中的splice和slice方法
  • 小程序开发之路(一)
  • 延迟脚本的方式
  • ​业务双活的数据切换思路设计(下)
  • #我与Java虚拟机的故事#连载11: JVM学习之路
  • (2)(2.4) TerraRanger Tower/Tower EVO(360度)
  • (动手学习深度学习)第13章 计算机视觉---微调
  • (附源码)基于SSM多源异构数据关联技术构建智能校园-计算机毕设 64366
  • (利用IDEA+Maven)定制属于自己的jar包
  • (四)图像的%2线性拉伸
  • (算法)求1到1亿间的质数或素数
  • (原創) 人會胖會瘦,都是自我要求的結果 (日記)
  • (转)MVC3 类型“System.Web.Mvc.ModelClientValidationRule”同时存在
  • (转)全文检索技术学习(三)——Lucene支持中文分词
  • (转)使用VMware vSphere标准交换机设置网络连接
  • (转载)VS2010/MFC编程入门之三十四(菜单:VS2010菜单资源详解)
  • ***原理与防范
  • .NET 8.0 中有哪些新的变化?
  • .NET Core WebAPI中使用swagger版本控制,添加注释
  • .net 反编译_.net反编译的相关问题
  • .Net高阶异常处理第二篇~~ dump进阶之MiniDumpWriter
  • .net和php怎么连接,php和apache之间如何连接
  • [04]Web前端进阶—JS伪数组
  • [Android学习笔记]ScrollView的使用
  • [BZOJ 4129]Haruna’s Breakfast(树上带修改莫队)
  • [BZOJ] 1001: [BeiJing2006]狼抓兔子
  • [CC-FNCS]Chef and Churu
  • [cocos2d-x]关于CC_CALLBACK
  • [codevs 2822] 爱在心中 【tarjan 算法】
  • [Django ]Django 的数据库操作