0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

c++引用详细解说3

jf_78858299 来源:阿Q正砖 作者:阿Q正砖 2023-02-15 09:43 次阅读

但是临时变量在哪?

  • 如果 c 比较小(4/8 byte),一般是寄存器充当临时变量,例如eax
  • 如果 c 比较大,临时变量放在调用 add 函数的栈帧中,

最后将临时变量中的值赋值给ret

图:

图片

所有的传值返回都会生成一个拷贝

便于理解,看一下汇编

图片

看第四句话,这里是说,把 eax 中的值,拷贝到 ret 中。

而再函数调用返回时:

图片

这里是将 c 的值放到 eax 中的。

这也就印证了返回时,是以临时拷贝形式返回的,由于返回值是 int ,所以是直接用的 eax 寄存器

而不论这个函数结束后,返回的那个值会不会被销毁,都会创建临时变量返回,例如这段代码 :

int fun(){            static int n = 0;        n++;        return n;}
int main(){ int ret = fun(); cout << ret << endl; return 0;}

对于该函数,编译器仍然是创建临时变量返回;因为编译器不会对其进行特殊处理。

看一下汇编:

图片

仍然是放到 eax 寄存器中返回的。

埋个伏笔:你觉不觉的这个临时变量创建的很冤枉,明明这块空间一直存在,我却依然创建临时变量返回了?能不能帮它洗刷冤屈。

如果我改成引用返回会发生什么情况吗?

int& add(int a, int b){            int c = a + b;            return c;}int main(){            int ret = add(1, 2);            cout << ret << endl;            return 0;}

引用返回就是不生成临时变量,直接返回 c 的引用。而这里产生的问题就是 非法访问 。

造成的问题:

  • 存在非法访问,因为 add 的返回值是 c 的引用,所以 add 栈帧销毁后,会访问 c 位置空间,而这是读操作,不一定检查出来,但是本质是错的。
  • 如果 add 函数栈帧销毁,空间被清理,那么取 c 值时取到的就是随机值,取决于编译器的决策。

ps:虽然vs销毁栈帧没有清理空间数据,但是会二次覆盖

来看个有意思的:

图片

例如这里,当调用 add 函数之后,返回 c 的引用,接收返回值是用的ret相当于是 c 的引用,这时由于没有清理栈帧数据,所以打印3;

但是第二次调用,重新建立栈帧,由于栈帧大小相同,第二次建立栈帧可能还是在原位置,之前空间的数据被覆盖,继续运算,但是此时,ret 那块空间的值就被修改了,而这时没有接收返回值,但是原先的那块 c 的值被修改,所以打印出来 ret 是 30 。

所以使用引用返回时,一旦返回后,返回值的空间被修改,那么都可能会造成错误,使用要小心!

引用返回有一个原则:如果函数返回时,出了函数作用域,如果返回对象还在(还没还给系统),则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。

它俩的区别就是一个生成拷贝,一个不生成拷贝。

而这时 static 修饰的静态变量不委屈了:

int& fun(){            static int n = 0;        n++;        return n;}

因为 static 修饰的变量在静态区,出了作用域也存在,这时就可以引用返回。

我们可以理解引用返回也有一个返回值,但是这个返回值的类型是 int& ,中间并不产生拷贝,因为返回的是别名。这就相当于返回的就是它本身。

有时引用返回可以发挥出意想不到的结果:

#include#define N 10typedef struct Array{            int a[N];            int size;}AY;
int& PostAt(AY& ay, int i){ assert(i < N); return ay.a[i];}int main(){ AY ay; PostAt(ay, 1); // 修改返回值 for (int i = 0; i < N; i++) { PostAt(ay, i) = i * 3; } for (int i = 0; i < N; i++) { cout << PostAt(ay, i) << ' '; } return 0;}

由于PostAt 的形参 ay 为 main 中 局部变量 ay的别名,所以 ay 一直存在;这时可以使用引用返回。

引用返回 减少了值拷贝 ,不比将其拷贝到临时变量中返回;并且由于是引用返回,我们也可以 修改返回对象 。

图片

总结提炼:如果出了作用域,返回变量(静态,全局,上一层栈帧,malloc等)仍然存在,则可以使用引用返回。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7551

    浏览量

    131928
  • C++
    C++
    +关注

    关注

    21

    文章

    2070

    浏览量

    73039
  • 面向对象
    +关注

    关注

    0

    文章

    64

    浏览量

    9936
收藏 人收藏

    评论

    相关推荐

    如何在MDK中使用C++,整理的经验

    一:C++引用C文件注意:C++文件能引用C文件,但是C
    发表于 03-10 15:32

    新手必备嵌入式学习步骤及方法详细解说

      新手必备嵌入式学习步骤及方法详细解说?嵌入式系统的应用非常广泛,因此对于计算机专业、电子信息专业、自动化专业以及机电一体化等专业的学生以及需要掌握嵌人式的人员来说,学习嵌入式系统及其开发应用是
    发表于 06-22 13:35

    详细讲解C++串口的相关知识

    大家可以先参考一下这篇blog,C++串口通信里面详细讲解了C++串口的相关知识,以及一些函数的讲解。下面我也会根据他的blog再讲解。二、实现过程1、打开串口:使用函数:HANDLE CreateFile();HANDLE C
    发表于 08-24 06:56

    IDF.PY编译时提示找不到iostream的原因?怎么才能正常引用iostream这些c++的标准库啊?

    failed with exit code 1我在工程里引用了一个C++的库,里面用了iostream, 在一个C++的.h头文件开头。c++类库我确认都在idf的对应目录下,包括i
    发表于 02-16 06:58

    请问ESP32+Eclipse如何添加C++生成得静态库(.a)如何引用

    ESP32在Eclipse下如何添加C++生成得静态库(.a)如何引用
    发表于 02-20 08:33

    开关电源原理及各功能电路详细解说

    开关电源原理及各功能电路详细解说
    发表于 09-15 17:19 42次下载
    开关电源原理及各功能电路<b class='flag-5'>详细</b><b class='flag-5'>解说</b>

    C++程序设计教程之数组的详细资料说明

    本文档详细介绍的是C++程序设计教程之数组的详细资料说明主要内容包括了:1. 数组的概念,2. 一维数组的定义和引用,3. 二维数组的定义和引用
    发表于 03-14 14:48 10次下载
    <b class='flag-5'>C++</b>程序设计教程之数组的<b class='flag-5'>详细</b>资料说明

    C++引用的使用场景

    C++引用的使用场景
    的头像 发表于 06-29 15:18 3873次阅读
    <b class='flag-5'>C++</b>:<b class='flag-5'>引用</b>的使用场景

    C++中的const和引用的讨论

    今天给大家分享一下这段时间学习c++的总结学习:c++里面的const关键字和引用
    的头像 发表于 12-24 15:35 692次阅读

    C++基础语法中的引用、封装和多态

    本期是C++基础语法分享的第六节,今天给大家来分享一下: (1)引用; (2)宏; (3)成员初始化列表; (4)封装; (5)继承; (6)多态; 引用 左值引用 常规
    的头像 发表于 09-12 09:58 1188次阅读

    c++引用详细解说1

    C++是C语言的继承,它可进行过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。
    的头像 发表于 02-15 09:40 427次阅读
    <b class='flag-5'>c++</b><b class='flag-5'>引用</b><b class='flag-5'>详细</b><b class='flag-5'>解说</b>1

    c++引用详细解说2

    C++是C语言的继承,它可进行过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。
    的头像 发表于 02-15 09:43 372次阅读
    <b class='flag-5'>c++</b><b class='flag-5'>引用</b><b class='flag-5'>详细</b><b class='flag-5'>解说</b>2

    c++引用详细解说4

    C++是C语言的继承,它可进行过程化程序设计,又可以进行以抽象数据类型为特点的基于对象的程序设计,还可以进行以继承和多态为特点的面向对象的程序设计。
    的头像 发表于 02-15 09:43 370次阅读
    <b class='flag-5'>c++</b><b class='flag-5'>引用</b><b class='flag-5'>详细</b><b class='flag-5'>解说</b>4

    C++引用和指针

    之前的文章我们已经介绍了C++中的基本类型如int,bool和double等,除了基本类型C++还有一些更复杂的数据类型复合类型,所谓的复合类型就是通过其他类型定义的类型,本篇文章我们将会着重介绍C++的复合类型
    的头像 发表于 03-17 14:00 476次阅读

    详细解说pcb板表面绝缘层

    详细解说pcb板表面绝缘层
    的头像 发表于 09-28 09:55 2378次阅读