C++初学者指南第一步---12.引用

C++初学者指南第一步—12.引用

文章目录

  • C++初学者指南第一步---12.引用
    • 1. 功能(和限制)
      • 1.1 非常量引用
      • 1.2 常量引用
      • 1.3 auto引用
    • 2.用法
      • 2.1 范围for循环中的引用
      • 2.2 常量引用的函数形参
      • 2.3 非常量引用的函数形参
      • 2.4 函数参数的选择:copy / const& / & ?
      • 2.5 避免输出型参数
    • 3.绑定规则
      • 3.1 右值和左值
      • 3.2 引用绑定规则
    • 4. 陷阱
      • 4.1 永远不要返回函数内部的对象引用!
      • 4.2 小心引用向量元素!
      • 4.3 避免生命周期延长!

1. 功能(和限制)

1.1 非常量引用

int   i = 2;
int& ri = i;  // 引用 i

ri 和 i 都指向相同对象/内存位置。

cout << i  <<'\n';   // 2
cout << ri <<'\n';   // 2
i = 5;
cout << i  <<'\n';   // 5
cout << ri <<'\n';   // 5
ri = 88;
cout << i  <<'\n';   // 88
cout << ri <<'\n';   // 88

运行上面代码

  • 引用不能为“null”,即它们必须始终指向一个对象。
  • 引用必须始终指向相同的内存位置。
  • 引用类型必须与被引用对象的类型一致。
int  i  = 2;
int  k  = 3;
int& ri = i;     // 引用 i
ri = k;          // 将 k 的值赋给 i(ri 的目标)
int& r2;         //  编译错误: 引用必须初始化
double& r3 = i;  //  编译错误:类型必须相同

1.2 常量引用

= 对象的只读访问

int i = 2;
int const& cri = i;  //  i 的常量引用
  • cri 和 i 都指向相同对象/内存位置。
  • 但 const 表示 i 的值无法通过 cri 更改。
cout << i   <<'\n';   // 2
cout << cri <<'\n';   // 2
i = 5;
cout << i   <<'\n';   // 5
cout << cri <<'\n';   // 5
cri = 88;  //  编译错误: 常量!

运行上面代码

1.3 auto引用

引用类型是从赋值符的右侧推导出来的。

int i = 2;           
double d = 2.023;       
double x = i + d;       
auto & ri = i;        // ri:  int &
auto const& crx = x;  // crx: double const&

运行上面代码

2.用法

2.1 范围for循环中的引用

std::vector<std::string> v;
v.resize(10);
// 修改vector中的元素:
for (std::string & s : v) { cin >> s; }
// 只读访问 vector 中的元素:
for (std::string const& s : v) { cout << s; }
// 修改:
for (auto & s : v) { cin >> s; }
// 只读访问:
for (auto const& s : v) { cout << s; }

2.2 常量引用的函数形参

只读访问 ⇒ const&

  • 避免高开销的副本
  • 向函数的用户清楚地传达只读意图

示例:计算中位数的函数
需要从向量中读取值!

错误:通过复制⇒值传递正确:通过 const& ⇒ 没有副本
int median (vector);
auto v = get_samples(“huge.dat”);
auto m = median(v);
// 运行时间和内存开销很大!
int median (vector const&);
auto v = get_samples(“huge.dat”);
auto m = median(v);
// 不复制 ⇒ 没有开销!

示例:混合传递(按引用 + 按值)

incl_first_last ({1,2,4},{6,7,8,9}) → {1,2,4,6,9}
incl_first_last ({1,2,4},{6,7,8,9}) → {1,2,4,6,9}

该实现是在第一个向量的本地副本 ‘x’ 上进行操作,并且通过常量引用 ‘y’ 从第二个向量中读取:

auto incl_first_last (std::vector<int> x, std::vector<int> const& y) {if (y.empty() return x;// append to local copy 'x'x.push_back(y.front());x.push_back(y.back());return x;
}

2.3 非常量引用的函数形参

示例:交换两个变量值的函数

void swap (int& i, int& j) {int temp = i;  // copy i's value to tempi = j;         // copy j's value to ij = temp;      // copy temp's (i's original value) to j
}
int main () {int a = 5;int b = 3;swap(a,b);cout << a << '\n'   // 3<< b << '\n';  // 5
}

运行上面代码
注意:可以使用 std::swap 来交换对象的值(#include )。它可以像上面的功能一样使用,但是可以避免对于支持移动语义的对象(如std::vector)的大开销的临时复制(它的实现将在移动语义章节中解释)。
虽然在某些情况下非 const 引用可能很有用,但总体上你还是应该避免使用这种输出参数(查看下面的内容获取更多细节)。

2.4 函数参数的选择:copy / const& / & ?

void read_from (int);  // 基本类型按值传递即可
void read_from (std::vector<int> const&);
void copy_sink (std::vector<int>);
void write_to  (std::vector<int> &);

从可以廉价复制的对象读取(所有基本类型)⇒ 值传递
如:

double sqrt (double x) { … }

从内存占用量较大(> 64位)的对象中读取内存时 ⇒ 用const &传递
如:

void print (std::vector<std::string> const& v) {for (auto const& s : v) { cout << s << ' '; }
}

在函数内部需要复制的内容 ⇒ 值传递
按值传递而不是在函数内显式复制。 其原因将在更高级的文章中解释。
如:

auto without_umlauts (std::string s) {s.replace('ö', "oe");  // modify local copy…return s;  // return by value!
}

写入到函数外部对象 ⇒ 由非常量&传递
(尽管它们在某些情况下可能很有用,但总的来说,你应该避免使用这种输出参数,请参阅下面内容。)
如:

void swap (int& x, int& y) { … }

2.5 避免输出型参数

像这样有非const引用参数的函数:

void foo (int, std::vector<int>&, double);

可能会在调用位置造成混乱/歧义:

foo(i, v, j);
  • 哪个参数 (i, v, j) 改变了,哪个保持不变?
  • 引用的对象是如何以及何时更改的,它是否被更改了?
  • 引用参数只充当输出(函数只向它写入数据)还是同时充当输入(函数也从它读取数据)?
    ⇒ 一般来说很难调试和推理!
    示例:一个只会造成混乱的接口
void bad_minimum (int x, int& y) {if (x < y) y = x;
}
int a = 2;
int b = 3;
bad_minimum(a,b);  
// 哪个变量再次保存了较小的值?

3.绑定规则

3.1 右值和左值

左值 = 我们可以获取内存地址的表达式

  • 指向持久存在内存中的对象
  • 一切有名称的东西(变量、函数参数……)

右值 = 我们无法获取内存地址的表达式

  • 字面值(123,“string literal”,…)
  • 临时的运行结果
  • 从函数返回的临时对象
int a = 1;      // a 和b 都是左值
int b = 2;      // 1 和 2 都是右值
a = b;
b = a;
a = a * b;      // (a * b)表达式的结果是右值
int c = a * b;  // OK,右值可以赋值给左值
a * b = 3;      //  编译错误:不能赋值给右值
std::vector<int> read_samples(int n) { … }
auto v = read_samples(1000);

3.2 引用绑定规则

&只能绑定到左值
const&可以绑定到const左值和右值

在这里插入图片描述

4. 陷阱

4.1 永远不要返回函数内部的对象引用!

在这里插入图片描述
只有在被引用对象的生命周期长于函数的情况下才有效!
在这里插入图片描述

4.2 小心引用向量元素!

警告:std::vector 中的元素引用可能在改变向量元素数量的任何操作之后失效!

vector<int> v {0,1,2,3};
int& i = v[2];
v.resize(20);  
i = 5; //  未定义行为:原始内存可能已经释放。

悬空引用 = 指的是指向一个不再有效的内存位置的引用。
std::vector 存储元素的内部内存缓冲区在某些向量操作期间可以被替换为新的缓冲区,因此对旧缓冲区的任何引用可能会变得悬空。

4.3 避免生命周期延长!

引用可以延长临时对象(右值)的生命周期。

auto const& r = vector<int>{1,2,3,4};
⇒ 向量对象的生命周期被引用 r 延长了

从函数返回的对象呢?

std::vector<std::string> foo () { … }
以值传递(推荐)
vector<string> v1 = foo();  
auto v2 = foo();
不推荐:忽略它→立即销毁
foo()
不推荐:获取对它的常量引用 ⇒ 临时对象的生命周期被延长
...只要这个引用还存在
vector<string> const& v3 = foo();  
auto const& v4 = foo();
禁止:不要引用它的成员
返回对象的成员(这里指向量的内容)不能延长生命周期!
string const& s = foo()[0];  // 悬空引用!
cout << s;                   //  未定义行为

不要通过引用来延长生命周期!

  • 容易造成混淆
  • 容易写出错误
  • 没有真正的好处

只需按值返回对象。 这对于现代C ++ 中的大多数函数和类型来说并不涉及大开销的复制,尤其是在C++17及更高版本中。

附上原文链接

如果文章对您有用,请随手点个赞,谢谢!^_^

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/361816.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

charles破解

一、Charles官网下载安装包二、安装charles三、charles破解 一、Charles官网下载安装包 根据自己电脑系统 官网下载即可。 链接: https://www.charlesproxy.com/download/latest-release/ 二、安装charles 点击下载的安装包&#xff0c;然后进行安装。 三、charles破解 打…

基于信息论的高动态范围图像评价算法matlab仿真

目录 1.程序功能描述 2.测试软件版本以及运行结果展示 3.核心程序 4.本算法原理 5.完整程序 1.程序功能描述 基于信息论的高动态范围图像评价算法matlab仿真&#xff0c;利用一种自然图像的概率模型对图像的熵与成像动态范围之间的关系进行了数值模拟,得到了具有普遍意义上…

如何制作自己的网站

制作自己的网站可以帮助个人或组织在互联网上展示自己的品牌、作品、产品或服务。随着技术的发展&#xff0c;现在制作网站变得越来越简单。下面是一个简单的步骤指南&#xff0c;帮助你制作自己的网站。 1. 确定你的网站需求和目标 在开始之前&#xff0c;你需要明确你的网站的…

国家自然科学基金标书大全(2002-2024)

数据来源&#xff1a;在20世纪80年代初&#xff0c;为了促进中国的科技体制革新并改革科研资金分配机制&#xff0c;中国科学院的89位院士联名向党和国家领导人提出建议&#xff0c;设立了国家自然科学基金的设立。国自然基金自创立以来&#xff0c;根据国家发展科学技术方针、…

群体优化算法---石墨烯优化算法介绍以及在期权定价上的应用(Black-Scholes模型来计算欧式期权的理论价格)

介绍 石墨烯算法是一种新兴的优化算法&#xff0c;灵感来自于石墨烯的结构和特性。石墨烯是一种由碳原子构成的二维蜂窝状晶格结构&#xff0c;具有优异的机械、电学和热学性能。石墨烯算法通过模拟石墨烯原子之间的相互作用和迁移&#xff0c;来求解复杂的优化问题 基本概念…

JavaEE之HTTP协议(1)_HTTP基础知识,HTTP 请求、响应格式,方法,状态码

一、HTTP协议 1.1 基本概念: HTTP全称超文本传输协议&#xff0c;是一种无状态的、应用层的协议&#xff0c;它基于请求/响应模型。客户端&#xff08;通常是Web浏览器&#xff09;通过发送HTTP请求到服务器来获取或发送信息&#xff0c;服务器则返回HTTP响应作为回应。HTTP协…

七天速通javaSE:第四天 递归算法

文章目录 前言一、递归的介绍二、递归模型&#xff08;n!&#xff09;1 阶乘的定义&#xff1a;2. 阶乘的递归代码实现3. 递推与回归的内部逻辑三、练习 前言 本文将学习递归算法。在计算机科学中&#xff0c;递归算法是一种将问题不断分解 为同一类子问题来解决问题的方法。递…

sd卡一插上就提示格式化是怎么回事?sd卡数据如何恢复?

sd卡一插上就提示格式化是怎么回事&#xff1f;里面的数据怎么办&#xff1f;下面小编总结了SD卡提示格式化的原因和对应解决办法分享给大家&#xff01; SD卡好好的&#xff0c;为什么一插电脑上就提示需要格式化呢&#xff1f;当SD卡提示格式化时&#xff0c;可以考虑下面几类…

项目1111

中文显示姓名列和手机号 SELECT contact_name AS 姓名, contact_phone AS 手机号 FROM 2_公司id; 使用explain测试给出的查询语句&#xff0c;显示走了索引查询 EXPLAIN SELECT * FROM 7_订单数量 WHERE countid LIKE e%; 统计用户订单信息&#xff0c;查询所有用户的下单数量…

项目实战系列三: 家居购项目 第六部分

文章目录 &#x1f308;Ajax检验注册名&#x1f308;Ajax添加购物车&#x1f308;上传与更新家居图片&#x1f308;作业布置&#x1f34d;会员登陆后不能访问后台管理&#x1f34d;解决图片冗余问题&#x1f34d;分页导航完善 &#x1f308;Ajax检验注册名 需求分析 注册会员时…

【osgEarth】Ubuntu 22.04 源码编译osgEarth 3.5

下载源代码 git clone --depth1 https://dgithub.xyz/gwaldron/osgearth -b osgearth-3.5 下载子模块 git submodule update --init 如果下载不过来&#xff0c;就手动修改下.git/config文件&#xff0c;将子模块的地址替换成加速地址 (base) yeqiangyeqiang-Default-string…

苹果Mac安装adobe软件报错“installer file may be damaged”解决方案

最近Mac电脑系统的有小伙伴在安装PS、AI、AE、PR等软件&#xff0c;出现了一个错误&#xff0c;让人头疼不已&#xff0c;苦苦找寻&#xff0c;也找不到完美的解决方法。让我们来一起看看吧&#xff01; 很多小伙伴都喜欢苹果电脑&#xff0c;但是在安装外来软件时&#xff0c;…

浏览器扩展V3开发系列之 chrome.cookies 的用法和案例

【作者主页】&#xff1a;小鱼神1024 【擅长领域】&#xff1a;JS逆向、小程序逆向、AST还原、验证码突防、Python开发、浏览器插件开发、React前端开发、NestJS后端开发等等 chrome.cookies API能够让我们在扩展程序中去操作浏览器的cookies。 在使用 chrome.cookies 要先声明…

电脑突然提示dll文件丢失,怎么选择正确的恢复方法?

电脑突然提示dll文件丢失&#xff1f;其实当你的电脑使用久了&#xff0c;出现这种dll文件丢失是非常的正常的&#xff0c;毕竟你总会有不恰当的操作吧&#xff1f;这些操作都是会导致dll文件丢失的。丢失了&#xff0c;我们直接进行相关的修复就好了&#xff0c;还是比较简单的…

【C++】运算符重载(日期类的实现)

文章目录 前言一、运算符重载的概念和意义二、运算符重载的规则三、常用运算符重载1.关系运算符重载2.赋值运算符重载3.、-、、-重载4.前置和后置重载5.流插入<<和流提取>>重载 前言 之前在总结类的六个默认成员函数时&#xff0c;没有过多介绍运算符重载&#xf…

文生视频模型Sora刷屏的背后的数据支持

前言&#xff1a;近日&#xff0c;OpenAI的首个文生视频模型Sora横空出世&#xff0c;引发了一波Sora热潮。与其相关的概念股连续多日涨停&#xff0c;多家媒体持续跟踪报道&#xff0c;央视也针对Sora进行了报道&#xff0c;称这是第一个真正意义上的视频生成大模型。 01 …

第三十三篇——互联网广告:为什么Google搜索的广告效果好?

目录 一、背景介绍二、思路&方案三、过程1.思维导图2.文章中经典的句子理解3.学习之后对于投资市场的理解4.通过这篇文章结合我知道的东西我能想到什么&#xff1f; 四、总结五、升华 一、背景介绍 对于信息的利用&#xff0c;再广告这个维度中去洞察&#xff0c;你又能发…

苹果CMS-V10 搭建教程踩坑,跳过部分验证

我突发奇想,想要安装一个CMS 苹果CMS搭建教程-CSDN博客 然后就有了下面的问题 结论是zip相关依赖未安装, 通过 apt install php-zip, 重新打开安装页面,同样如此 最后依据某个网站提示,修改 "\\192.168.1.200\root\var\www\html\maccms\application\install\control…

鸿蒙系统最简单安装谷歌服务及软件的方法

哈喽&#xff0c;各位小伙伴们好&#xff0c;我是给大家带来各类黑科技与前沿资讯的小武。 近日&#xff0c;华为开发者大会在东莞松山湖召开&#xff0c;发布了盘古大模型5.0和纯血版的鸿蒙 HarmonyOS NEXT 全场景智能操作系统&#xff0c;而根据研究机构 Counterpoint Resea…

AWS云计算平台:全方位服务与实践案例

摘要 在数字化浪潮的推动下&#xff0c;云计算已成为企业转型的强大引擎。AWS作为云计算的先锋&#xff0c;不仅提供了一系列强大的基础设施服务&#xff0c;更是在人工智能领域不断探索和创新。本文将带您领略AWS的全方位服务&#xff0c;并透过实际案例&#xff0c;感受其在…