【C++】作用域,生命周期和常用存储类型

简介: 有关作用域、生命周期的记录

写在前面

大家好,我是翼同学。今天文章的内容是:

  • 作用域,生命周期和常用存储类型

内容

作用域

在C++中,变量分为全局变量和局部变量,这种划分依据是由变量的可见范围决定的,或者说是:作用域。

image.png

生命周期

我们把变量可以被使用的时间段称为生命周期。

不同生命周期的变量,在程序内存中的位置也不一样,通常一个程序的内存会分为:

  • 代码区
  • 全局数据区
  • 堆区
  • 栈区

如下所示:

image.png

变量在不同区域则对应不同的生命周期。

下面是程序内存的分布情况:

image.png

存储类型

生命周期只是和变量存储的位置有关,而变量的存储类型可分为两种:

  • 静态存储(在程序运行时,系统对变量分配固定的存储空间)
  • 动态存储(在程序运行时,系统对变量分配不固定的存储空间,即动态地分配)

一般的,变量的常用存储类型有四种:

  • auto:自动变量
  • register:寄存器变量
  • static:静态变量
  • extern:外部变量

注意:

  • 从 C++ 11 开始,auto关键字不再是C++存储类说明符,且register关键字被弃用。
  • 自动变量和寄存器变量属于动态存储,外部变量和静态变量属于静态存储。

(1) auto存储

用法:

  • 可用于声明函数时函数返回值的占位符
  • 可用于声明变量时,系统自动根据初始化表达式自动推导该变量的类型

image.png

注意:

在C++98标准中,函数内未加存储类型说明的变量均视为自动变量(但C++11中已删除这一用法)

(2) register存储

用法:

  • 可用于定义存储在寄存器中而不是 RAM (运行内存)中的局部变量.
  • 可用于使用需要快速访问的变量,而不用去访问内存.
  • 对于循环次数较多的变量,均可定义为寄存器变量.

注意:

  • 只有局部变量才能定义为寄存器变量,因为其属于动态存储方式.
  • 变量被定义register后不一定就真的存储在寄存器中,这取决于硬件的限制.

(3) static存储

用法:

  • 修饰局部变量时,可使其在进入或离开作用域时不用被创建和销毁
  • 修饰全局变量时,会使变量的作用域限制在声明它的文件内

image.png

小结:

  • 静态局部变量是一种生存期为整个源程序的变量。虽然离开定义它的函数后仍无法使用它,但一旦再次调用函数时,它又可以继续使用,而且保存了前次被调用后留存的值
  • 静态全局变量使其无法在同一源程序的其他源文件中使用,这可以避免在其他源文件中操作失误而引起错误。

(4) extern存储

外部变量和全局变量其实是对同一类变量的两种看法,全局变量是从作用域的角度去看,外部变量是从存储方式提出。

我们知道,一个源程序由若干个源文件组成。当我们在一个源文件中把变量说明为外部变量时,也就是用extern去修饰,那么表示这个变量是外部的,在其他文件中已被定义过,此时系统不再为变量分配内存空间。

用法:用于两个及多个源文件共享同一个全局变量或函数(函数也能共享)

(5) 小结

当然,存储类型不止上述四种:

  • mutable存储类型:仅适用于类对象,它允许对象的成员替代常量,即mutable成员可以通过const成员函数修改。
  • thread_local存储类型:使用thread_local说明符声明的变量仅可在它在其上创建的线程上访问。它是C++11新引入的存储类型。有且只有thread_local关键字修饰的变量具有线程周期,这使得变量在线程开始的时候被生成,在线程结束的时候被销毁。thread_local还可以和staticextern关键字联合使用。

image.png

写在最后

好了,文章的内容就到这里,感谢观看。

目录
相关文章
|
2月前
|
存储 编译器 程序员
C++类型参数化
【10月更文挑战第1天】在 C++ 中,模板是实现类型参数化的主要工具,用于编写能处理多种数据类型的代码。模板分为函数模板和类模板。函数模板以 `template` 关键字定义,允许使用任意类型参数 `T`,并在调用时自动推导具体类型。类模板则定义泛型类,如动态数组,可在实例化时指定具体类型。模板还支持特化,为特定类型提供定制实现。模板在编译时实例化,需放置在头文件中以确保编译器可见。
39 11
|
3月前
|
安全 程序员 C语言
C++(四)类型强转
本文详细介绍了C++中的四种类型强制转换:`static_cast`、`reinterpret_cast`、`const_cast`和`dynamic_cast`。每种转换都有其特定用途和适用场景,如`static_cast`用于相关类型间的显式转换,`reinterpret_cast`用于低层内存布局操作,`const_cast`用于添加或移除`const`限定符,而`dynamic_cast`则用于运行时的类型检查和转换。通过具体示例展示了如何正确使用这四种转换操作符,帮助开发者更好地理解和掌握C++中的类型转换机制。
|
4月前
|
C++
使用 QML 类型系统注册 C++ 类型
使用 QML 类型系统注册 C++ 类型
88 0
|
5月前
|
存储 Prometheus Cloud Native
SLS Prometheus存储问题之为什么SLS时序引擎最终选择了使用C++实现PromQL的部分算子
SLS Prometheus存储问题之为什么SLS时序引擎最终选择了使用C++实现PromQL的部分算子
|
5月前
|
编译器 C++ 运维
开发与运维函数问题之函数的返回类型如何解决
开发与运维函数问题之函数的返回类型如何解决
41 6
|
5月前
|
安全 编译器 C++
C++一分钟之-模板元编程实例:类型 traits
【7月更文挑战第15天】C++的模板元编程利用编译时计算提升性能,类型traits是其中的关键,用于查询和修改类型信息。文章探讨了如何使用和避免过度复杂化、误用模板特化及依赖特定编译器的问题。示例展示了`is_same`类型trait的实现,用于检查类型相等。通过`add_pointer`和`remove_reference`等traits,可以构建更复杂的类型转换逻辑。类型traits增强了代码效率和安全性,是深入C++编程的必备工具。
93 12
|
4月前
|
存储 C++
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
【C/C++学习笔记】string 类型的输入操作符和 getline 函数分别如何处理空白字符
51 0
|
5月前
|
C++
C++一分钟之-类型别名与using声明
【7月更文挑战第20天】在C++中,类型别名和`using`声明提升代码清晰度与管理。类型别名简化复杂类型,如`using ComplexType = std::vector<std::shared_ptr<int>>;`,需注意命名清晰与适度使用。`using`声明引入命名空间成员,避免`using namespace std;`全局污染,宜局部与具体引入,如`using math::pi;`。恰当应用增强代码质量,规避常见陷阱。
87 5
|
4月前
|
设计模式 安全 IDE
C++从静态类型到单例模式
C++从静态类型到单例模式
40 0
|
5月前
|
C++ 开发者
C++一分钟之-概念(concepts):C++20的类型约束
【7月更文挑战第4天】C++20引入了Concepts,提升模板编程的类型约束和可读性。概念定义了模板参数需遵循的规则。常见问题包括过度约束、约束不完整和重载决议复杂性。避免问题的关键在于适度约束、全面覆盖约束条件和理解重载决议。示例展示了如何用Concepts限制模板函数接受的类型。概念将增强模板的安全性和灵活性,但需谨慎使用以防止错误。随着C++的发展,Concepts将成为必备工具。
111 2