C++ 内存模型

news/2025/1/25 9:22:26/

一、单独编译

1.1、常见程序结构

C++鼓励程序员将组件函数放到独立的文件中,下面是一种常用的组织文件的策略,如下

  • 头文件:包含结构声明和使用这些结构的函数的原型
  • 源代码文件:包含与结构有关的函数的代码
  • 源代码文件:包含调用与结构相关的函数的代码

下面列出了头文件中常包含的内容,如下:

  • 函数原型
  • 使用#define或const定义的符号常量
  • 结构声明
  • 类声明
  • 模板声明
  • 内联函数

1.2、引用自定义头文件

如果文件名包含在尖括号中,则C++编译器将在存储标准头文件的主机系统的文件系统中查找;但如果头文件包含在双引号中,则编译器将首先查找当前的工作目录或源代码目录。如果没有在那里找到头文件,则将在标准位置查找。因此,在包含自己的头文件时,应使用引号而不是尖括号。

二、存储持续性、作用域和链接

C++使用三种(在C++11中是四种)不同的方案来存储数据,这些不同方案的区别就在于数据保留在内存的时间。

  • 自动存储持续性:在函定义中声明的变量(包括函数参数)的存储持续性为自动的。它们在程序开始执行其所属的函数或代码块时被创建,在执行完函数或代码块时,它们使用的内存被释放。C++有2种存储持续性为自动的变量。
  • 静态存储持续性:在函数定义外定义的变量和使用static关键字定义的变量的存储持续性都为静态。它们在程序整个运行过程中都存在。C++有3种存储持续性为静态的变量。
  • 线程存储持续性(C++ 11):如果变量是使用thread_local声明的,则其生命周期与所属的线程一样长。
  • 动态存储持续性:使用new运算符分配的内存将一直存在,直到使用delete释放申请的内存或程序结束为止。这种内存的存储持续性为动态,有时被称为自由存储或堆。

2.1、自动存储持续性

在函数声明中的函数参数和变量的存储持续性为自动,作用域为局部,没有连接性。如下:

void display(int x, int y) {// 局部变量,存储持续性为自动、作用域为局部、没有连接性int z = x + y;cout << "x + y = " << z << endl;
}

2.2、静态存储持续性

和C语言一样,C++也为静态存储持续性变量提供了3种连接性:外部连接性(可在其他文件中访问)、内部连接性(只能在当前文件中访问)和无连接性(只能在当前函数或代码块中访问)。这3种连接性都在整个程序执行期间存在,与自动变量相比,它们的寿命更长,编译器会分配固定的内存块来存储所有的静态变量。此外,如果没有显示初始化静态变量,编译器把它设置为0。如下:

// 全局变量,连接性为外部,可以在多个文件间共享
int g_count = 10;// 全局静态变量,连接性为内存,只能在当前文件中访问
static int one_file = 20;double display(int x, int y) {// 局部静态变量,没有连接性,只能在当前代码块内访问static int local_count = 50;return x + y;
}int main()
{double x = 2.0;double y = 3.0;cout << display(x, y) << endl;return 0;
}

注意:如果初始化静态局部变量,则程序只在启动时进行一次初始化。以后再调用函数时,将不会像自动变量那样再次被初始化。

可使用外部变量在多文件程序的不同部分之间共享数据,可使用连接性为内部的静态变量在同一个文件的多个函数之间共享数据。此外,如果将作用域为整个文件的变量变为静态的,就不必担心其名称与其它文件的作用域为整个文件的变量发生冲突。

三、单定义规则

C++有单定义规则(One Definition Rule,ODR),该规则指出变量只能有一次定义。为了满足这种需求,C++提供了两种变量声明。一种是定义声明或简称为定义,它给变量分配存储空间;另一种是引用声明或简称为声明,它不给变量分配存储空间,因为它引用已有的变量。引用声明使用extern关键字,且不能进行初始化;否则声明为定义,导致分配存储空间。如下:

// file01.cpp
extern int g_count = 20; // 定义变量g_count// file02.cpp
extern int g_count;  // 引用全局变量g_count

如果需要在多个文件中使用外部变量,只需要在一个文件中包含该变量的定义,但是在使用该变量的其他文件中,都必须使用extern关键字声明它。

四、存储说明符与限定符

4.1、存储说明符

有些被称为存储说明符限定符的C++关键字提供了其他有关存储的信息,下面是存储说明符,如下:

  • auto(在C++11不再是说明符)
  • register
  • static
  • extern
  • thread_local(C++11新增的)
  • mutable

4.2、cv限定符(cv表示const和volatile)

最常用的cv限定符是const,它对默认存储类型有影响。在默认情况下全局变量的连接性为外部的,但const全局变量的连接性为内部的。如下:

// const全局变量的连接性为内部的
const int g_count = 10;

为什么头文件可以放置const定义?

C++修改了常量类型的规则,让程序员更轻松。例如:假设将一组常量放到头文件中,并在同一个程序的多个文件中使用该头文件。那么,预处理器将头文件的内容包含到每个源文件后,所有的源文件都包含类似下面这样的定义,如下:

const int g_god = 10;
const int g_cat = 20;
const char *g_name = "jack";

如果全局const声明的链接性像常规变量那样是外部的,将违反单定义规则。也就是说,只有一个文件包含前面的声明,其它文件必须使用extern关键字来提供引用声明。内部链接性意味着,每个文件都有自己的一组常量,而不是所有的文件共享一组常量,每个定义都是文件私有的,这就是能够将常量定义放到头文件的原因。

五、函数与链接性

和变量一样函数也有链接性,和C语言一样C++不允许在一个函数内部定义另一个函数,因此所有函数的存储持续性都自动为静态的,即在整个程序执行期间都一直存在。默认情况下函数的链接性是外部的,即可以在文件间共享。可以使用extern关键字来指出函数是在另外一个文件中定义的,还可以使用static关键字将函数的链接性声明为内部的,如下:

// 函数链接性默认是外部的
void display(int x, int y) {cout << x << y << endl;
}

单定义规则也适用于函数,因此,对于每个非内联函数,程序只能包含一个定义。内联函数不受该规则的约束,这允许程序员能将内联函数的定义放在头文件中。这样,包含了头文件的每个文件都有内联函数的定义。然而,C++要求同一个函数的所有内联定义都必须相同。


http://www.ppmy.cn/news/68279.html

相关文章

Kettle获取接口数据到表

kettle从接口服务获取数据 主要用到kettle输入菜单下的控件&#xff1a;生成记录、JSON input 查询菜单下的控件&#xff1a;HTTP client 输出菜单下的控件&#xff1a;表输出、插入/更新 生成记录&#xff1a;设置一个变量&#xff0c;用这个变量来保存要去访问接口的URL地址…

英语基础句型之旅:从基础到高级

英语句型之旅&#xff1a;从基础到高级 一、起步&#xff1a;掌握英语基础句型 (Getting Started: Mastering Basic English Sentence Structures)1.1 英语句子的基本构成 (The Basic Components of English Sentences)1.2 五大基本句型解析 (Analysis of the Five Basic Sente…

【算法数据结构体系篇class38】对数器找规律、根据数据状况猜解法(续)、以及分治

一、对数器找规律 1)某个面试题,输入参数类型简单,并且只有一个实际参数 2)要求的返回值类型也简单,并且只有一个 3)用暴力方法,把输入参数对应的返回值,打印出来看看,进而优化code 二、题目一 小虎去买苹果,商店只提供两种类型的塑料袋,每种类型都有任意数量。

全国标杆!3DCAT实时云渲染助力深圳移动5G+智慧校园建设

2023年2月27日&#xff0c;中国移动在陕西西安召开全国教育行业全年工作部署暨电子学生证专项调度会&#xff0c;来自全国各地的移动分公司、专家、合作伙伴等参加了会议。瑞云科技旗下3DCAT实时渲染云作为中国移动的重要合作伙伴之一&#xff0c;也受邀出席进行项目展示。 在会…

PBDB Data Service:Single fossil collection(单一化石采集记录)

Single fossil collection&#xff08;单一化石采集记录&#xff09; 描述用法参数以下必需参数选择要检索的记录您还可以使用以下参数来指定要检索的信息 方法响应结果1. basic2. refattr3. secref4. loc5&#xff1a;bin6&#xff1a;paleoloc7&#xff1a;prot8&#xff1a;…

【C++进阶2--多态】面向对象三大特性之一,多种形态像魔法?

今天&#xff0c;带来C多态的讲解。 多态和继承并用&#xff0c;能产生“魔法般的效果”。 *文中不足错漏之处望请斧正&#xff01; 见见多态 是什么 使得父类指针或引用有多种形态。 怎么使它有多种形态呢&#xff1f;咱们先见见猪跑。 见见猪跑 class Base { public:v…

vue-admin-template 后台模版初始化及问题汇总

参考&#xff1a;https://segmentfault.com/a/1190000023185109?sortvotes 问题一&#xff1a;Unsupported engine 后来经过分析&#xff0c;发现&#xff0c;element-ui 的版本依赖锁定是在一个叫做package-locak.json 中&#xff0c;并且找到了相关配置。 package-lock.js…

【操作系统】《2023 南京大学 “操作系统:设计与实现” (蒋炎岩)》- 知识点目录

《2023 南京大学 “操作系统&#xff1a;设计与实现” (蒋炎岩)》 1. 操作系统概述 (操作系统的历史&#xff1b;学习建议) [南京大学2023操作系统-P1] 1.1 Z3库&#xff1a;解决逻辑定理证明问题 Z3是由微软研究院开发的一个高效的定理证明器&#xff0c;用于解决逻辑定理证…