详解C++中的自动存储

C++有3种管理数据内存的方式即自动存储(栈存储)、静态存储和动态存储(堆存储)。在不同的方式下,内存的分配形式和存在时间的长短都不同。

下面对自动存储进行说明。

自动存储(栈存储)

对于函数的形参、内部声明的变量及结构变量等,编译器将在函数执行时为形参自动分配存储空间,在执行到变量和结构变量等的声明语句时为其自动分配存储空间,因此称其为自动变量(Automatic Variable),有的教科书也称其为局部变量,在函数执行完毕返回时,这些变量将被撤销,对应的内存空间将被释放。

事实上,自动变量的生存期只局限于它所在的代码块。所谓代码块,是包含在花括号对中的一段代码,函数只是代码块的一种,比较下面两段代码。

代码段1

int add(int m,int n)

{

  //z的生存期包括整个函数

  int z=m+n;

  return z;

}

代码段2

int add(int m,int n)

{

  if(m!=0)

  {

    //z的生存期包括在这个代码块中

    int z=m+n;

  }

  return z;//错误

}

在代码段1中,当函数返回时,变量z被撤销,对应内存空间被释放,但在代码段2中,在if代码块中声明的变量z,其生存期仅限于if结构的两个花括号之间,当程序执行到if结构的后花括号时,变量z已被撤销,其对应的内存空间被释放,此时,再执行“return z;”语句便会出错。

注意

理解代码块的含义十分重要,花括号不是判断代码块的唯一标准,把代码段2中if结构的花括号去掉,代码仍然是错误的,将“return z;”放在if结构中是正确的用法。

自动变量的生存期是局部的,这一特性使得程序员可以在不同的块内使用相同的变量名,用不着为使用不同的变量名绞尽脑汁。

1.什么是“栈”

栈(Stack)是一块存储区,而且是C++程序使用最频繁的存储区,其存储机理为“FILO”,即先进后出(First In,Last Out)。可以将其想象成一个装盘子的桶,最早放入的盘子在桶的底部,最晚放入的盘子在最顶部,取盘子时必须先从后放进去的盘子开始取,这就是所谓的先进后出原则。当一个代码块(包括函数,视为一种特殊的代码块)声明一个自动变量时,系统便为其在栈中开辟内存空间(常称“压入”push),该代码块结束后便将自动变量撤销,释放内存空间(常称“弹出”pop)。

注意

采用“栈”这种机制,C++程序能有效地节省所用内存空间。

2.auto关键字

auto是C++提供的存储类声明符,用于声明自动变量,除了auto声明符外,C++还提供了另外3个存储类声明符,分别是register(寄存器存储)、extern(外部存储)和static(静态存储)。在声明创建变量时,存储类声明符应放在数据类型声明符之前,如下所示。

存储类声明符 数据类型 变量名[=初始化表达式]

其中,初始化表达式是可选的,如下列代码声明创建了int型自动变量A,其只在函数demo()执行期间存在,demo()函数执行完毕后,变量A被撤销,对应内存被释放。

void demo()

{

  ……

  auto int A;

  ……

}

在前面给出的示例代码在声明自动变量时并没有加auto修饰符,实际上,auto常常可以默认,凡是在函数内部(不论是main()函数还是其他函数)的,没有用其他显式的存储类型声明符,编译器都认为是auto型自动变量。

3.register关键字

除了auto外,还可以通过存储类声明符register来声明自动变量,与auto唯一的不同在于:关键字register通知编译器,用户希望通过CPU寄存器,而不是“栈”来处理某个变量,从而可以在一定程度上加快该变量的访问速度。

提示

一般来说,CPU对寄存器的访问要快过对内存的访问。

用register声明的变量常称为寄存器变量,举例来说,下列代码声明了int型寄存器变量sum,并将其初始化为9,如下所示。

register int sum=9;

需要注意的是,即使用register声明了某个变量,编译器也不一定会满足它的要求。因为,CPU寄存器可能被占用或者无法存储指定类型的数据等,而且,现在的编译器一般可以自动决定应把哪些变量放在CPU寄存器中,因此,在C++程序中,register关键字很少使用。

使用register关键字会带来一定的负面效果,不管是否能满足要求,编译器认为register型自动变量是存储在CPU寄存器中的,而寄存器是没有内存地址的,所以,不能对register型自动变量进行取地址操作,下列代码是错误的。

void demo()

{

  ……

  register int sum=0;

  int*pSum=∑

  ……

}

注意

事实上,用auto和register声明的变量除了存储位置不同(一个是“栈”,而另一个可能是“栈”也可能是CPU寄存器)外,并无其他差异,我们可以将其统称为自动变量来考虑。

4.自动变量的初始化

可以在声明自动变量时对其进行初始化,也可以使用任何具有确定值的表达式为自动变量赋值,下列语句都是合法的(假定n为int型自动变量)。

n=2;

n=5*m;//m的值确定

n=add(4,6);

需要特别注意的是,如果没有在自动变量声明的同时对其初始化,其初始值是随机、不可预料的,为避免随机的初始值给程序带来麻烦,推荐在声明自动变量的同时对其显式初始化。

以上就是详解C++中的自动存储的详细内容,更多关于C++ 自动存储的资料请关注我们其它相关文章!

(0)

相关推荐

  • 深度剖析C++对象池自动回收技术实现

    对象池可以显著提高性能,如果一个对象的创建非常耗时或非常昂贵,频繁去创建的话会非常低效.对象池通过对象复用的方式来避免重复创建对象,它会事先创建一定数量的对象放到池中,当用户需要创建对象的时候,直接从对象池中获取即可,用完对象之后再放回到对象池中,以便复用.这种方式避免了重复创建耗时或耗资源的大对象,大幅提高了程序性能.本文将探讨对象池的技术特性以及源码实现. 对象池类图 ObjectPool:管理对象实例的pool. Client:使用者. 适用性: 类的实例可重用. 类的实例化过程开销较大.

  • win10环境下vscode Linux C++开发代码自动提示配置(基于WSL)

    安装 vs code, 安装 c/c++ 插件 C/C++ IntelliSense,TabNine,Bracket Pair Colorizer. 在win10下打开linux子系统设置(具体搜索教程),在应用商店安装ubutu16. 打开File->Preferences->settings,编辑settings.json. copy 以下的内容替换settings.json "C_Cpp.default.compilerPath": "/usr/bin/g+

  • 基于C++自动化编译工具的使用详解

    @echo off  title=HYTradingGateway自动化编译打包工具mode con cols=80 lines=40echo -------------------------------------------------------------echo 使用说明echo.                                                             echo HYTradingGateway自动化编译打包工具.修改echo 使用前提

  • c++ 让程序开机自动启动的方法

    当我们在window下编写自己的程序时,也可以让自己编写的程序在电脑开机时自动运行,这主要是修改windows里的注册表信息,所有开机自动启动的程序的一些信息都放在注册表中的某一文件夹下.我们只需在特定的文件夹下写入我们的程序信息即可. 关于注册表 我们可以在键盘上同时按下 win+r 键,在运行串口中输regedit 回车即可看到注册表(可以理解为一个大树,记录着系统中的信息),我们点击左边文件夹,点击顺序为:Software\\Microsoft\\Windows\\CurrentVersi

  • C++自动生成迷宫游戏

    本文实例为大家分享了C++实现迷宫游戏的具体代码,供大家参考,具体内容如下 运用并查集自动生成迷宫地图,并运用队列和栈寻找迷宫通路并打印出来 #include<stdlib.h> #include<iostream> #include<time.h> #include<queue> #include<stack> using namespace std; using std::queue; using std::stack; typedef st

  • C++自动析构时的顺序问题

    自动析构时是先析构后构造的. //普通(非模板)类的成员模板 class DebugDelete{ public: DebugDelete(ostream &s = cerr) :os(s){} template <typename T>void operator()(T*p)const { os << "deleting unique_ptr " <<typeid(T).name() <<endl; delete p; } pr

  • 不要被C++(自动生成规则)所蒙骗

    C++对象可以使用两种方式进行创建:构造函数和复制构造函数.假如我们定义了类A,并使用它创建对象. 复制代码 代码如下: A a,b; A c=a; A d(b); 对象a和b使用编译器提供的默认构造函数A::A()创建出来,我们称这种创建方式为对象的定义(包含声明的含义).对象c和d则是使用已有的对象,通过编译器提供的复制构造函数A::A(const A&)创建,我们称这种创建方式为对象的初始化(包含定义和声明的含义). 可能不少人会把对象的初始化和对象的赋值混淆,比如. 复制代码 代码如下:

  • VC++实现CStdioFile写入及读取文件并自动换行的方法

    本文所述CStdioFile可实现在VC++中主要用来写入及读出文件的功能,继承自CFile类,它会自动处理 "\r\n",遇到"\n"自动添加\r并设置光标在当前行,它同时可以自动换行,不过使用CStdioFile在处理大文件时速度有些慢, 用CStdioFile写入读取文件实现代码如下: LPTSTR filter=_T("Playlist Files(.txt)|*.txt|"); CString tempPath; CFileDialog

  • 详解C++中的自动存储

    C++有3种管理数据内存的方式即自动存储(栈存储).静态存储和动态存储(堆存储).在不同的方式下,内存的分配形式和存在时间的长短都不同. 下面对自动存储进行说明. 自动存储(栈存储) 对于函数的形参.内部声明的变量及结构变量等,编译器将在函数执行时为形参自动分配存储空间,在执行到变量和结构变量等的声明语句时为其自动分配存储空间,因此称其为自动变量(Automatic Variable),有的教科书也称其为局部变量,在函数执行完毕返回时,这些变量将被撤销,对应的内存空间将被释放. 事实上,自动变量

  • 详解Android 中的文件存储

    目录 概要 当我们查看手机的文件管理器的时候,会发现里面的文件五花八门,想要找到自己项目所对应的文件非常困难,甚至有可能压根就找不到自己的文件,本文就来介绍一下APP开发过程当中文件存储的注意事项. 通常我们会将存放的文件分为两种:独立文件和专属文件.顾名思义,独立文件就是独立于APP之外的文件,不会随着APP的删除而删除,而专属文件则是专属于某个APP的文件,当APP删除后,会自动清空相对应的专属文件. 独立文件 独立文件指的是存放在shared/external storage direct

  • 详解Python中如何将数据存储为json格式的文件

    一.基于json模块的存储.读取数据 names_writer.py import json names = ['joker','joe','nacy','timi'] filename='names.json' with open(filename,'w') as file_obj: json.dump(names,file_obj) 解释:我们先导入json模块,再创建一个名字列表,第5行我们指定了要将该列表存储到其中的文件的名称.通常使用扩展名.json来指出文件存储的数据为json格式.

  • 详解mysql中的存储引擎

    mysql存储引擎概述 什么是存储引擎? MySQL中的数据用各种不同的技术存储在文件(或者内存)中.这些技术中的每一种技术都使用不同的存储机制.索引技巧.锁定水平并且最终提供广泛的不同的功能和能力.通过选择不同的技术,你能够获得额外的速度或者功能,从而改善你的应用的整体功能. 例如,如果你在研究大量的临时数据,你也许需要使用内存存储引擎.内存存储引擎能够在内存中存储所有的表格数据.又或者,你也许需要一个支持事务处理的数据库(以确保事务处理不成功时数据的回退能力). 这些不同的技术以及配套的相关

  • 详解MySql中InnoDB存储引擎中的各种锁

    目录 什么是锁 InnoDB存储引擎中的锁 锁的算法 行锁的3种算法 幻像问题 锁的问题 脏读 不可重复读 丢失更新 死锁 什么是锁 现实生活中的锁是为了保护你的私有物品,在数据库中锁是为了解决资源争抢的问题,锁是数据库系统区别于文件系统的一个关键特性.锁机制用于管理对共享资源的并发访. 数据库系统使用锁是为了支持对共享资源进行并发访问,提供数据的完整性和一致性 InnoDB存储引擎区别于MyISAM的两个重要特征就是:InnoDB存储引擎支持事务和行级别的锁,MyISAM只支持表级别的锁 In

  • 详解Python中4种超参自动优化算法的实现

    目录 一.网格搜索(Grid Search) 二.随机搜索(Randomized Search) 三.贝叶斯优化(Bayesian Optimization) 四.Hyperband 总结 大家好,要想模型效果好,每个算法工程师都应该了解的流行超参数调优技术. 今天我给大家总结超参自动优化方法:网格搜索.随机搜索.贝叶斯优化 和 Hyperband,并附有相关的样例代码供大家学习. 一.网格搜索(Grid Search) 网格搜索是暴力搜索,在给定超参搜索空间内,尝试所有超参组合,最后搜索出最优

  • 详解MySQL中存储函数创建与触发器设置

    目录 1.创建存储函数 2.调用存储函数 3.创建触发器 4.在触发器中调用存储过程 5.删除触发器 存储函数也是过程式对象之一,与存储过程相似.他们都是由SQL和过程式语句组成的代码片段,并且可以从应用程序和SQL中调用.然而,他们也有一些区别: 1.存储函数没有输出参数,因为存储函数本身就是输出参数. 2.不能用CALL语句来调用存储函数. 3.存储函数必须包含一条RETURN语句,而这条特殊的SQL语句不允许包含于存储过程中 1.创建存储函数 使用CREATE FUNCTION语句创建存储

  • 详解Electron中如何使用SQLite存储笔记

    目录 前言 数据库的选择 安装 创建表 Service Controller 业务 总结 前言 上一篇,我们使用 remirror 实现了一个简单的 markdown 编辑器.接下来,我们要学习如何去存储这些笔记. 当然了,你也可以选择不使用数据库,不过若是你以后需要将该应用上架到 mac Apple Store ,就需要考虑这个了.因为上架 mac 应用需要启用 sandbox,当你第一次访问笔记中的媒体文件时,都要打开选择文件的弹窗,通过让用户主动选择来授权访问沙箱外的媒体文件.不过,如果你

  • 详解C++中存储类的使用

    目录 auto 存储类 register 存储类 static 存储类 extern 存储类 mutable 存储类 存储类定义 C++ 程序中变量/函数的范围(可见性)和生命周期.这些说明符放置在它们所修饰的类型之前.下面列出 C++ 程序中可用的存储类: auto register static extern mutable auto 存储类 在C++11 中, auto 关键字不再是C++存储类说明符.从C++11开始,auto 关键字声明一个变量,该变量的类型是从其声明中的初始化表达式推

  • 详解Java中HashSet和TreeSet的区别

    详解Java中HashSet和TreeSet的区别 1. HashSet HashSet有以下特点: 不能保证元素的排列顺序,顺序有可能发生变化 不是同步的 集合元素可以是null,但只能放入一个null 当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置. 简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个

随机推荐