草庐IT

【开懂C++】引用与关键字auto

Aomnitrix 2023-12-12 原文


目录

一.引用

1.引用的概念

引用就是给一个已经存在的变量取一个别名,与变量共用一段内存空间。注意引用的类型必须和变量类型相同,来演示下引用如何使用。

#include <iostream>
using namespace std;

int main()
{
	int a = 1;
	int& b = a;
	int& c = b;
	int& d = c;
	
	cout << &a << endl;
	cout << &b << endl;
	cout << &c << endl;
	cout << &d << endl;

	return 0;
}

如上面的代码所示:我们给a取了个别名b,给b取别名c…也就是b是a的引用,c是b的引用…。其实b,c,d都代表着a,它们都共用着一块内存空间
如下图所示:

2.引用的使用和问题

引用的注意事项:

  1. 引用必须初始化
  2. 引用不能更改
  3. 一个变量可以有多个引用

引用可以作为函数的参数也可以做返回值,在之前学习C语言我们常使用指针传参,也就是传址调用来改变外部变量的值。学习引用后,我们只用引用传参就会特别方便。
当返回引用时,就会引出很多问题,这里我们来解析下下面的代码:

int& Add()
{
	int n = 0;//静态变量static int a = 0;
	n++;

	return n;
}

int main()
{
	int ret=Add();
	cout << ret << endl;
	return 0;
}

n在Add函数中变为1,Add返回了n的引用,我们用变量ret来接收n的引用也就是n的值,但是有个问题就是——n在出Add函数后函数栈帧如果被清理的话,函数返回引用找到的值就会是随机值。如果栈帧没有被清理,那ret侥幸是正确的1。为了避免这种情况我们可以将Add函数的n设为静态变量
为了验证,我们再看一下面的代码:

int& Add(int x)
{
	int n = x;
	n++;
	return n;
}

int main()
{
	int& ret=Add(10);
	cout << ret << endl;

	Add(20);
	rand();
	cout << ret << endl;
	return 0;
}

假设出Add函数后栈帧不破坏那打印结果就是11\n21,但是我们调用个函数,模拟函数栈帧破坏的情况,那结果是不是像我们预想的那样为随机值呢。

总结
引用传参适合大部分的情况
将引用返回值时需要注意引用对象还是否出函数是否还存在

下面我们来看引用使用场景及其优点:
1.引用做参数-(输出型参数)
2.引用做参数-(减少拷贝提高效率) (大对象/深拷贝类对象)
3.引用做返回值-(减少拷贝提高效率) (大对象/深拷贝类对象)
4.引用做返回值-修改返回值+获取返回值

接下来再讲一下常引用、引用权限的放大、缩小、平移:

int func()
{
	stctic int a=0;
	a++;
	return a;
}
int main()
{
	//引用的权限可以平移和缩小不可以放大
	int a = 0;
	int& b = a;//平移
	const int& c = a;//缩小
	++a;
	++c;//放大


	const int a = 10;
	int& b = a;//只能给变量取别名

	double c = 3.14;
	int& d = c;//引用的类型需要匹配
	const int& e = c;//类型转换会创建临时变量 临时变量具有常量性质

	int& ret=func();//权限放大
	return 0;
}

语法层面上引用不会开空间知识对变量取得一个别名,而从底层汇编指令来看的话引用是类似指针的方式使用的。

3.引用与指针的比较

引用和指针有许多不同点:

  1. 引用需要初始化,指针不要求
  2. 引用不能修改,指针可以
  3. 有空指针,没有空引用
  4. 引用更为安全,指针可能出现野指针和越界等情况
  5. 在sizeof中引用是类型的字节大小,指针是根据机器位数来判断字节个数
  6. 引用在语法上定义一个变量的别名,指针储存一个变量的地址
  7. 有多级指针没有多级引用
  8. 指针需要根据地址解引用访问,引用是编译器自己处理的

二.关键字auto

auto可以自动识别类型,当类型过于复杂冗长时,auto使用起来非常的方便。

int main()
{
	int a = 1;
	auto b = 10;
	auto c = 3.14;
}

在同一行定义多个变量时,需要注意同一行的变量类型要一致,不然auto无法正确识别:

int main()
{
	auto a = 1, b = 2; 
 	auto c = 3, d = 4.0;//类型不同
}

auto还不能作为函数的参数以及定义数组

auto还有个重要的应用——范围for循环
他提供了一种更简便的for遍历的方法根据冒号”:”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示迭代的范围。

int main()
{

	int arr[] = { 0,1,2,3,4,5,6 };

	for (auto x : arr)
		cout << x << endl;
}

有关【开懂C++】引用与关键字auto的更多相关文章

  1. ruby - 一个 YAML 对象可以引用另一个吗? - 2

    我想让一个yaml对象引用另一个,如下所示:intro:"Hello,dearuser."registration:$introThanksforregistering!new_message:$introYouhaveanewmessage!上面的语法只是它如何工作的一个例子(这也是它在thiscpanmodule中的工作方式。)我正在使用标准的ruby​​yaml解析器。这可能吗? 最佳答案 一些yaml对象确实引用了其他对象:irb>require'yaml'#=>trueirb>str="hello"#=>"hello"ir

  2. ruby - Ruby 的 AST 中的 'send' 关键字是什么意思? - 2

    我正在尝试学习Ruby词法分析器和解析器(whitequarkparser)以了解更多有关从Ruby脚本进一步生成机器代码的过程。在解析以下Ruby代码字符串时。defadd(a,b)returna+bendputsadd1,2它导致以下S表达式符号。s(:begin,s(:def,:add,s(:args,s(:arg,:a),s(:arg,:b)),s(:return,s(:send,s(:lvar,:a),:+,s(:lvar,:b)))),s(:send,nil,:puts,s(:send,nil,:add,s(:int,1),s(:int,3))))任何人都可以向我解释生成的

  3. ruby - 未定义的方法 auto_upgrade!将 Sinatra/DataMapper 应用程序推送到 Heroku 时 - 2

    有谁知道在Heroku的Bamboo堆栈上启动并运行使用DataMapper的Sinatra应用程序所需的魔法咒语?Bamboo堆栈不包含任何预安装的系统gem,无论我尝试使用何种gem组合,我都会不断收到此错误:undefinedmethod`auto_upgrade!'forDataMapper:Module(NoMethodError)这是我的.gems文件中的内容:sinatrapgdatamapperdo_postgresdm-postgres-adapter这些是我将应用程序推送到Heroku时安装的依赖项:----->Herokureceivingpush----->Si

  4. ruby - Chef LW 资源属性默认值如何引用另一个属性? - 2

    我正在尝试将一个资源属性的默认值设置为另一个属性的值。我正在为我正在构建的tomcat说明书定义一个资源,其中包含以下定义。我想要可以独立设置的“名称”和“服务名称”属性。当未设置服务名称时,我希望它默认为为“名称”提供的任何内容。以下不符合我的预期:attribute:name,:kind_of=>String,:required=>true,:name_attribute=>trueattribute:service_name,:kind_of=>String,:default=>:name注意第二行末尾的“:default=>:name”。当我在Recipe的新block中引用我

  5. ruby - 在 Ruby 中,为什么 Array.new(size, object) 创建一个由对同一对象的多个引用组成的数组? - 2

    如thisanswer中所述,Array.new(size,object)创建一个数组,其中size引用相同的object。hash=Hash.newa=Array.new(2,hash)a[0]['cat']='feline'a#=>[{"cat"=>"feline"},{"cat"=>"feline"}]a[1]['cat']='Felix'a#=>[{"cat"=>"Felix"},{"cat"=>"Felix"}]为什么Ruby会这样做,而不是对object进行dup或clone? 最佳答案 因为那是thedocumenta

  6. ruby - 引用具有指定索引的枚举器值 - 2

    假设我有一个可枚举对象enum,现在我想获取第三个项目。我知道一种通用方法是转换成数组,然后使用索引访问,如:enum.to_a[2]但这种方式会创建一个临时数组,效率可能很低。现在我使用:enum.each_with_index{|v,i|breakvifi==2}但这非常丑陋和多余。执行此操作最有效的方法是什么? 最佳答案 你可以使用take剥离前三个元素,然后剥离last从take给你的数组中获取第三个元素:third=enum.take(3).last如果您根本不想生成任何数组,那么也许:#Ifenumisn'tanEnum

  7. ruby - 为什么 return 关键字会导致我的 'if block' 出现问题? - 2

    下面的代码工作正常:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson)do|key,oldv,newv|ifkey==:aoldvelsifkey==:bnewvelsekeyendendputskerson.inspect但是如果我在“ifblock”中添加return,我会得到一个错误:person={:a=>:A,:b=>:B,:c=>:C}berson={:a=>:A1,:b=>:B1,:c=>:C1}kerson=person.merge(berson

  8. ruby - 在 Ruby 中跳过额外的关键字参数 - 2

    我定义了一个方法:defmethod(one:1,two:2)[one,two]end当我这样调用它时:methodone:'one',three:'three'我得到:ArgumentError:unknownkeyword:three我不想从散列中一个一个地提取所需的键或排除额外的键。除了像这样定义方法之外,有没有办法规避这种行为:defmethod(one:1,two:2,**other)[one,two,other]end 最佳答案 如果不想写**other中的other,可以省略。defmethod(one:1,two:2

  9. ruby - 在多个线程中引用类方法会导致自动加载循环依赖崩溃 - 2

    代码:threads=[]Thread.abort_on_exception=truebegin#throwexceptionsinthreadssowecanseethemthreadseputs"EXCEPTION:#{e.inspect}"puts"MESSAGE:#{e.message}"end崩溃:.rvm/gems/ruby-2.1.3@req/gems/activesupport-4.1.5/lib/active_support/dependencies.rb:478:inload_missing_constant':自动加载常量MyClass时检测到循环依赖稍加研究后,

  10. Ruby 泄露的对象被 RubyVm::Env 引用 - 2

    我正在跟踪我们的应用程序(ruby2.1)中的内存泄漏问题。我正在使用这两种技术:ObjectSpace.dump_all将所有对象转储到JSON流,然后进行离线分析。我使用的第二种技术是使用ObjectSpace.reachable_objects_from进行实时分析。在这两种方式中,我发现我泄漏的对象被一个对象RubyVM::Env引用。任何人都可以向我解释什么是RubyVM::Env。如何删除这些引用? 最佳答案 RubyVM::Env是一个包含变量引用的内部ruby​​类。这是我的测试:require'objspace'a

随机推荐