第三周周总结

news2024/11/28 10:50:24

# 1.内存各分区的顺序问题
上周我简单介绍了内存分区:[内存分区](http://192.168.6.130/wiki/#/view/20/1482)

代码区
-   **程序启动时**:当程序开始执行时,首先会加载代码区。操作系统将可执行文件中的代码段加载到内存的代码区,这其中包含了程序的所有指令,这些指令是 CPU 执行的依据,程序的执行流从代码区的起始位置开始,按照指令的顺序依次执行。
-   **整个程序运行期间**:代码区的内容在程序运行过程中一般是只读的,不允许被修改。这是为了保证程序的指令的稳定性和安全性 ,防止程序在运行过程中由于误操作或恶意修改而导致程序崩溃或出现不可预测的行为。

常量区
-   **程序启动时或首次访问常量时**:常量区在程序启动时通常也会随着程序的加载而被初始化,它用于存放程序中的常量数据,如字符串常量、const 修饰的全局常量和字面量等。这些常量在程序运行期间是不可修改的。当程序中首次访问到某个常量时,相关的常量数据就会被加载到常量区。
-   **整个程序运行期间**:在程序运行的整个生命周期内,常量区的数据都保持不变,可供程序的各个部分共享和访问。多个地方使用相同的常量时,实际上都是指向常量区中的同一个存储位置,这样可以节省内存空间并提高程序的运行效率。

栈区
-   **函数调用时**:当程序调用一个函数时,会在栈区为该函数分配一块栈帧,用于存储函数的局部变量、函数参数、返回地址等信息。栈帧的大小在编译时就大致确定,函数执行完毕后,栈帧会被自动释放,其所占用的栈空间也会被回收。这种分配和释放的方式遵循 “后进先出” 的原则,即最后进入栈的函数最先退出并释放栈帧。
-   **嵌套函数调用时**:如果存在嵌套的函数调用,每进入一层新的函数调用,就会在栈顶为新的函数分配一个新的栈帧,随着函数调用的层层深入,栈区的空间会不断增长;而当函数依次返回时,栈帧会依次被弹出,栈区的空间逐渐缩小。

堆区
-   **动态内存分配时**:堆区的内存分配和释放是由程序员手动控制的,通过`new`、`malloc`等操作符在程序运行期间动态地申请内存空间。当程序需要使用一块在编译时无法确定大小的内存时,就会在堆区进行动态内存分配。
-   **动态内存释放时**:在使用完动态分配的内存后,必须通过`delete`、`free`等操作符显式地释放内存,否则会导致内存泄漏,即这块内存一直被占用,直到程序结束才会被操作系统回收。堆区的内存分配和释放时间完全由程序员根据程序的逻辑来决定,因此其使用顺序相对比较灵活,但也需要程序员更加谨慎地管理内存,以避免出现内存错误。

## 1.1 代码示例
```
#include <iostream>  
using namespace std;  
  
// 用于记录内存分配相关顺序的全局变量  
int globalOrder = 0;  
  
// 自定义类,用于观察构造和析构情况,辅助展示内存区域特点  
class MyClass {  
public:  
 int num;  
 MyClass(int n) : num(n) {  
 cout << "构造对象,值为" << num << " ,分配顺序: " << ++globalOrder << endl;  
 }  
 ~MyClass() {  
 cout << "析构对象,值为" << num << endl;  
 }  
};  
  
// 全局对象,存放在全局区  
MyClass globalObj(1);  
  
// 函数声明,函数代码存放在代码区  
void func();  
  
// 特殊函数,用来模拟在代码区靠前部分执行的操作  
void initFunction() {  
cout << "执行initFunction,这部分代码在代码区靠前位置执行" << endl;  
}  
  
// 函数定义,同样代码存放在代码区,这里体现函数本身的代码所在区域  
void func() {  
 MyClass stackObj(2);   // 局部对象,存放在栈区  
 MyClass* heapObj = new MyClass(3);  // 在堆区动态分配对象  
 cout << "堆区对象地址: " << heapObj << endl;  
 delete heapObj;  
}  
  
int main() {  
 // 代码区的代码从main函数开始按顺序执行  
 initFunction();  
 cout << "程序开始,先观察全局区对象情况" << endl;  
 func();  
 cout << "函数调用结束,继续执行主函数后续部分" << endl;  
 return 0;  
}
```
运行结果为:

![image.png](doc-wiki/common/file?uuid=uIkbCkPtopSsGmtFGluu5t)

如果我将`调用构造函数创建对象`和`new一个对象`调换一下顺序。
```
// 函数定义,同样代码存放在代码区,这里体现函数本身的代码所在区域 
void func() {  
 MyClass* heapObj = new MyClass(3); // 在堆区动态分配对象  
 MyClass stackObj(2); // 局部对象,存放在栈区   
 cout << "堆区对象地址: " << heapObj << endl;  
 delete heapObj;  
}
```
会发现在堆的执行顺序就比栈的高了,说明二者在执行时并没有明确的先后顺序之分。

![image.png](doc-wiki/common/file?uuid=oCDeXDr0Qr3gDAK3n7RVlf)

从上面的运行结果貌似可以得出以下结论:全局区的代码会首先执行,其加载时间点是在main函数之前的;然后程序开始执行(main函数开始执行);在程序中根据代码逻辑的不同,栈区和堆区才会先后进行加载。
在更复杂的程序中,栈区和堆区的使用先后顺序完全取决于代码的具体逻辑和功能需求。

但是这种结论存在一些误区。
## 1.2 常量区和代码区的加载顺序
**加载**:一般情况下,在程序启动时,操作系统会先将可执行文件中的代码段加载到内存的代码区,之后才会在代码执行过程中,当需要访问常量时,再将常量加载到常量区(常量区是按需加载的)。因为代码区存放着程序的指令,是程序执行的基础,CPU 需要先获取这些指令才能开始执行程序的逻辑,如函数调用、循环控制等操作。从这个角度说,代码区先于常量区被加载。
在进入 `main` 函数之前,C++ 运行时环境会负责执行一系列的初始化操作,这些操作包括对全局对象和静态对象的初始化,这也是为什么上面的示例中全局区的代码会优先于main函数的执行,全局区的对象首先进行了初始化。
## 1.3 常量区和代码区的执行顺序
**执行**:

-   **代码区主导运行流程**
    -   程序的运行是以代码区的指令顺序为基础展开的。CPU 从代码区的起始地址开始,按照指令的先后顺序依次执行,每一条指令决定了程序下一步的操作,如进行数据运算、调用其他函数、进行内存访问等。整个程序的运行流程完全由代码区的指令所控制和引导。
    -   以一个包含多个函数的程序为例,`main`函数中的指令首先被执行,当遇到调用其他函数的指令时,CPU 会暂停`main`函数的执行,转而跳转到被调用函数在代码区的指令位置开始执行,被调用函数执行完毕后,再返回`main`函数继续执行后续的指令。
-   **常量区配合代码区运行**
    -   常量区在运行时主要是为代码区的指令提供所需的常量数据支持。当代码区的指令需要使用某个常量时,例如进行数据比较、赋值操作或作为函数的参数等,就会从常量区读取相应的常量值。常量区的常量在程序运行过程中一般是只读的,不会被程序随意修改,以确保程序的稳定性和数据的一致性。
    -   例如,在一个计算圆面积的程序中,代码区的指令在计算过程中需要使用圆周率`3.14`这个常量,当执行到相关计算指令时,就会从内存的常量区获取`3.14`这个值,然后与半径值进行运算,从而得到圆的面积。

# 2. nullptr_t
上周对NULL和nullptr进行了一些区别的总结:[NULL和nullptr](http://192.168.6.130/wiki/#/view/20/1619)
这里对 `nullptr_t` 进行一些分享:
## 2.1 nullptr_t 介绍 
首先再介绍一下`nullptr`,`nullptr` 是一种特殊的常量,表示空指针,其类型是 `std::nullptr_t`。使用 `nullptr` 可以避免上述类型歧义的问题。
`nullptr_t` 是表示 `nullptr` 的类型的类型名。它是一个特殊的类型,可以用来声明和定义接受或返回 `nullptr` 的变量或函数。
## 2.2 特性

1.所有定义为 `nullptr_t` 类型的数据都是等价的,行为也是完全一致的。
2. `nullptr_t` 类型数据可以隐式转换成任意一个指针类型,但是不能转化为非指针类型,即使使用reinterpret_cast<nullptr_t>()的方式也不可以。
3. `nullptr_t` 类型数据不用于算术运算表达式,可以用于关系运算表达式(仅限于`nullptr_t`类型数据或者指针类型数据进行比较)
## 2.3 特殊情况
虽然nullptr_t看起来像是个指针类型,但是**在把nullptr_t应用于模板中时,模板会把它作为一个普通的类型来进行推导**,并不会将其视为T*指针。以下是一个示例:
```
template<typename T>
void g(T* t){}
 
template<typename T>
void h(T t){}
 
int main(int argc, char *argv[])
{
    g(nullptr);         //编译失败,因为nullptr的类型是nullptr_t,而不是指针
    g((float*) nullptr);//推导出T=float
 
    h(0);               //推导出T=int
    h(nullptr);         //推导出T=nullptr_t
    h((float*)nullptr); //推导出T=float*
}
```
 

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【C++习题】15.滑动窗口_串联所有单词的子串

文章目录 题目链接&#xff1a;题目描述&#xff1a;解法C 算法代码&#xff1a;图解 题目链接&#xff1a; 30. 串联所有单词的子串 题目描述&#xff1a; 解法 滑动窗口哈希表 这题和第14题不同的是&#xff1a; 哈希表不同&#xff1a;hash<string,int>left与right指…

【学术讲座】视觉计算中的深度学习方法 AIGC图像视频生成模型的推理加速

视觉计算中的深度学习方法 发展历程 backbone 强化学习、LLM等&#xff1a;有监督 && 无监督的结合 目标检测 图像分割 网络结构搜索 搜索方法 1&#xff1a;强化学习 2&#xff1a;强化学习 3&#xff1a;梯度算法 结构选择的作用 1&#xff1a;开放环境感知网络…

【VLANPWN】一款针对VLAN的安全研究和渗透测试工具

关于VLANPWN VLANPWN是一款针对VLAN的安全研究和渗透测试工具&#xff0c;该工具可以帮助广大研究人员通过对VLAN执行渗透测试&#xff0c;来研究和分析目标VLAN的安全状况。该工具专为红队研究人员和安全学习爱好者设计&#xff0c;旨在训练网络工程师提升网络的安全性能&…

机器学习之数据预处理理论——基于表格数据分析

一、机器学习中数据预处理的作用与目的 对于机器学习而言&#xff0c;数据预处理是指在数据挖掘、数据分析、模型构建训练等过程中&#xff0c;对原始数据进行一系列的处理&#xff0c;以提高数据质量、减少噪声、提取有用信息等。数据预处理的主要目的是将原始数据转换为有用的…

如何写出好证明(支持思想的深入数学写作)

不断的修改和精炼是写作过程中的重要环节&#xff0c;数学写作最终目的是提供对问题的深刻洞察而非仅仅陈述细节。 根据harvey mudd college Francis Su教授的《GUIDELINES FOR GOOD MATHEMATICAL WRITING》讲稿&#xff0c;总结出撰写好的数学证明需要注意以下几个要点&#x…

中英双语介绍DeepSpeed 的 ZeRO 优化

DeepSpeed 的 ZeRO 优化&#xff1a;通俗易懂的原理与实践指南 引言 在深度学习的大规模模型训练中&#xff0c;显存瓶颈是常见的挑战。DeepSpeed 提供了革命性的 ZeRO (Zero Redundancy Optimizer) 优化技术&#xff0c;为大模型训练节省显存、提高效率提供了强有力的工具。…

如何将 GitHub 私有仓库(private)转换为公共仓库(public)

文章目录 如何将 GitHub 私有仓库转换为公共仓库步骤 1: 登录 GitHub步骤 2: 导航到目标仓库步骤 3: 访问仓库设置步骤 4: 更改仓库可见性步骤 5: 确认更改步骤 6: 验证更改注意事项 如何将 GitHub 私有仓库转换为公共仓库 在软件开发领域&#xff0c;GitHub 是一个广受欢迎的…

【webrtc】 mediasoup中m77的IntervalBudget及其在AlrDetector的应用

IntervalBudget 用于带宽控制和流量整形 mediasoup中m77 代码的IntervalBudget ,版本比较老IntervalBudget 在特定时间间隔内的比特预算管理,从而实现带宽控制和流量整形。 一。 pacedsender 执行周期: 下一次执行的时间的动态可变的 int64_t PacedSender::TimeUntilNextPr…

Z2400023基于Java+Servlet+jsp+mysql的酒店管理系统的设计与实现 源码 调试 文档

酒店管理系统的设计与实现 1.摘要2.主要功能3. 项目技术栈运行环境 4.系统界面截图5.源码获取 1.摘要 本文介绍了一个基于Java的酒店管理系统&#xff0c;该系统采用Servlet、JSP、JDBC以及c3p0等技术构建&#xff0c;为酒店提供了一个全面的管理平台。该系统不仅适合酒店进行…

《操作系统 - 清华大学》5 -5:缺页异常

文章目录 1. 缺页异常的处理流程2.在何处保存未被映射的页&#xff1f;3. 虚拟内存性能 1. 缺页异常的处理流程 缺页中断的处理过程: CPU读内存单元&#xff0c;在TLB中根据其虚拟地址匹配物理地址&#xff0c;未命中&#xff0c;读页表; 由于页表项的存在位为0&#xff0c;CP…

C++:多态的原理

目录 一、多态的原理 1.虚函数表 2.多态的原理 二、单继承和多继承的虚函数表 1、单继承中的虚函数表 2、多继承中的虚函数表 一、多态的原理 1.虚函数表 首先我们创建一个使用了多态的类&#xff0c;创建一个对象来看其内部的内容&#xff1a; #include<iostre…

Ubuntu 硬盘分区并挂载

一、什么是挂载 1.挂载的定义 在 Ubuntu&#xff08;或其他 Linux 系统&#xff09;中&#xff0c;挂载&#xff08;Mount&#xff09; 是将一个存储设备或分区连接到系统的文件系统层次结构中的过程。挂载后&#xff0c;你可以通过某个目录&#xff08;挂载点&#xff09;访问…

python-docx -- 读取word页眉、页脚

文章目录 sections介绍访问section添加section页眉、页脚综合案例:sections介绍 word支持section的概念,即一个文档的划分部分,不同的部分均包含相同的页面布局设置,如相同的边距、页面方向等;在每个section中可以定义页眉、页脚来应用于该section下的所有页面;大部分wor…

开源加密库mbedtls及其Windows编译库

目录 1 项目简介 2 功能特性 3 性能优势 4 平台兼容性 5 应用场景 6 特点 7 Windows编译 8 编译静态库及其测试示例下载 1 项目简介 Mbed TLS是一个由ARM Maintained的开源项目&#xff0c;它提供了一个轻量级的加密库&#xff0c;适用于嵌入式系统和物联网设备。这个项…

《生成式 AI》课程 第7講:大型語言模型修練史 — 第二階段: 名師指點,發揮潛力 (兼談對 ChatGPT 做逆向工程與 LLaMA 時代的開始)

资料来自李宏毅老师《生成式 AI》课程&#xff0c;如有侵权请通知下线 Introduction to Generative AI 2024 Springhttps://speech.ee.ntu.edu.tw/~hylee/genai/2024-spring.php 摘要 这一系列的作业是为 2024 年春季的《生成式 AI》课程设计的&#xff0c;共包含十个作业。…

公司金融期末考试题目

公司金融期末考试题 选择题 1.现金折扣和信用条件&#xff08;教材P253&#xff09; 题目类似&#xff1a; 下列不属于信用条件的是&#xff08;&#xff09;。 现金折扣 数量折扣信用期限 折扣期限 给定的信用条件为"1/10&#xff0c;n/40"&#xff0c;则其含义…

【前端】JavaScript中的字面量概念与应用详解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: 前端 文章目录 &#x1f4af;前言&#x1f4af;字面量1. 数字字面量2. 字符串字面量3. 布尔字面量4. 空值字面量&#xff08;null&#xff09;5. 对象字面量6. 数组字面量7. 正则表达式字面量8. 特殊值字面量9. 函数字…

Kotlin DSL Gradle 指南

本文是关于 Kotlin DSL Gradle 的指南&#xff08;上篇&#xff09;&#xff0c;介绍了 Gradle 作为 Android 开发构建工具的作用及优势&#xff0c;包括初始配置、生命周期、依赖管理、Task 相关内容。如 Task 的创建、自定义、各种方法和属性&#xff0c;以及文件操作等&…

Web开发:使用stackexchange.redis库对redis进行增删改查

一、安装第三方库 二、官网 StackExchange.Redis |通用型 redis 客户端 三、连接示例 private static string redisConnectionString "localhost:6379,passwordyourpassword,defaultDatabase0,allowAdmintrue,asyncTimeout10000";private static string redisConn…

2024年第15届蓝桥杯C/C++组蓝桥杯JAVA实现

目录 第一题握手&#xff0c;这个直接从49累加到7即可&#xff0c;没啥难度&#xff0c;后面7个不握手就好了&#xff0c;没啥讲的&#xff0c;(然后第二个题填空好难&#xff0c;嘻嘻不会&#xff09; 第三题.好数​编辑 第四题0R格式 宝石组合 数字接龙 最后一题:拔河 第…