C++感受10-Hello Object 生死版•下

搞懂以下三个重要知识点:

  1. 对象生命周期
  2. 对象内存模型
  3. 对象的可见性

 

ff12-HelloObject-生死版-下

1. 生命周期

只要是数据,就需要占用内存空间。程序将内存分成多个区,其中最重要的是栈区和堆区。放在栈区的数据,称为栈数据或栈对象;放在堆区的数据,称为堆数据或堆对象。二者最大的不同,在于数据的生命周期不同。

1.1 栈数据的生命周期

在栈区内存中的数据,它们什么时候死,是由所在代码结构决定的。最典型的,C/C++中,函数、流程结构(比如之前学习的 if/esle、while)等,所拥有的一对花括号,即形成一个语句块(也称代码块)。栈数据会在所在的最内层代码块结束出“死亡”;且遵循同一层级的栈数据,“先定义的后死,后定义的先死” 的原则。

  • 例1:
int main()
{
    Object o;
    return 0;    
}

 本例,o的生命周期始于定义,终于 main () 函数体的 } 之前 (即,在return 0 之后)。

  • 例2:
int main()
{
    Object o1;
    Object o2; 
}

01和02都将在函数体结束处死亡,但o1先定义故后死,o2后定义故先死。

  • 例3:
int main()
{  
     {
         Object o1;
     }

    Object o2;    
}

本例,o1 拥有独立的代码块,代码块处于 o2定义之前,因此 o1 将先生也先死。

  • 栈对象生命周期测试完整代码:
#include <iostream>

using namespace std;

struct Object1 
{ 
   Object1() { cout << "哥生" << endl; }
   ~Object1() { cout << "哥死" << endl; }
};

struct Object2
{ 
   Object2() { cout << "弟生" << endl; }
   ~Object2() { cout << "弟死" << endl; }
};

void test1()
{
   Object1 o1; 
   Object2 o2;
}

void test2()
{
  {  Object1 o1; }
   Object2 o2;
}

int main()
{
    test1();   
    cout << "~~~~~\n";
    test2();   
}

1.2 堆数据的生命周期

1.2.1 创建堆数据的语法

类型名 * 对象名 = new 类型名();

当不初始化初值,或类型(结构)的构造函数不需要入参时,() 可省略。
另外,很多情况下,上面的两处类型名完全相同,此时可使用 C++11 标准,将第一个类型名用 auto 代替,如:

auto* o = new Object(); 
或:
auto* o = new Object; 
内置类型数据,也可在堆中创建,并且可以 在上述语法中的 () 填写初始值 ,比如:
int* i = new int(12); // 创建 名为 i 的 int 类型堆变量,且初始值为 12 

更多例子如:

int* i = new int; 
int* age = new int(12); // 带入参构造 
char* c = new char(‘A’); 
double* money = new double; 
bool* sheLoveMe = new bool(false); 
auto* year = new int (2024); 

1.2.2 杀死堆数据的语法

一个堆数据创建出来,且分配了堆内存后,如果不释放,它将一直存活(直到程序退出)。“杀死”常规堆数据的语法是:

delete 对象名;

如(结构类型数据):

auto* o = new Object;

// 使用 o 

delete o;

 或(内置类型数据):

int i = new i(12);

cout << *i << endl; // 将输出 12 , *i 解释见后

delete i; // 杀死!

1.2.3 堆数据的生命周期

从 new 创建并获得堆内存开始,到被代码主动 delete 之间,堆数据都是“活”的(即一直在占用堆区的内存);下面的例子中,函数 foo()每被调用一次,都将在堆内存中占用一字节内存,并且在每一次调用结束后都未释放该内存,从而造成 “内存泄漏” 。

void foo()
{
   bool* b = new bool (false);
   std::cout << b << std::endl;
}

int main()
{
   foo();
}

2. 内存模型

 

2.1 栈对象内存模型

栈对象内存模型

 代码:

void foo()
{
   int age = 12;
}

foo() 被调用时,将创建一个类型为 int 的栈数据,该数据初始值为 12。此值存放在栈区;在特定系统下, int 占用 4个字节的内存。

一个字节的内存,类似于一间不可再分的房间;每一字节的内存都拥有一个地址,类似于房间的门牌号。图中 12 所存放的四个字节的内存地址为 8001~8004 。

实际内存地址数值通常比较大,此处为形像易理解,故意简化为类似门牌号码;另外,内存的存入次序,也不一定是如图中的从小到大排列。

通常称第一个字节的地址,为数据的存储地址,即图中 12 的存储地址为 8001。

2.2 堆对象内存模型

代码:

void foo()
{
    int* age = new int(12);
}

执行时,将首先在栈内存中占用固定大小的内存(64位系统下固定为8字节,32位系统下固定为4字节);同时在堆中申请并获得(至少)可存放一个 int 的堆内存(特定系统下为 4 字节),并将初始值 12 存放于其中,再将其地址存放于栈中分配的内存里,本例为 1126540。

此过程,至少涉及两个内存地址,一个在栈内存,即图中的 8001,一个在堆内存,即图中的 1126540。

当一块内存中存放的是另一块内存的地址,我们就称前一块内存指向后一块内存。在本例中,即地址为 8001 的栈内存,指向地址为 1126540 的堆内存。

此时,也可将两个地址视为两个数据,则称前一数据为指针数据或指针变量,即,示例中的 age 是一个指针变量,它指向的内容,则使用 “*age” 表示。

由于 age (即指针变量) 存储在栈中,因此也遵循栈区数据的规矩:会依据所在代码块的结束而自动回收。即:图示中的地址为 8001 的八字节栈内存,会在 foo() 函数的结束时,自动退还,而因为没有 delete ,未能归还的内存,是存放 12 的,四个字节的堆内存。

想要释放指针变量所指向的内存,如前所述,语法 delete 指针变量。示例如下:

void foo()
{
    int* age = new int(12);
    
    delete age; // 正确写法
    delete *age; // 错误写法
}

3. 可见区域

通过四个例子代码加以了解数据的可见区域。

  • 例1:
int test1()
{
   int i;
   int i;   // 错误
}

说明:同一生命周期内,存在完全同名的两个数据,非法。 

  • 例2:
int test2()
{
   int i;

   {
      i = 999; // 外部的i
      int i;   
      i = 888;  // 内部的i
   }
}

说明:嵌套(包括多级嵌套)的内部代码块,可以看见及访问外部代码块之前定义的数据(例中:i = 999),除非内部代码块出现同名数据,此时看见的内部的同名数据(例中:i = 888)。 

  • 例3:
int test3()
{
   {
      int i;
   }

   i = 999; // 错误
}

说明:外部的代码块,看不到哪位位于其前定义的内部代码块中定义的数据。 

  • 例4:
int test4()
{
   {
      auto* i = new int;
   }

   delete i; // 错误
}

说明:外部的代码块,看不到哪位位于其前定义的内部代码块中定义的数据,哪怕其前定义的内部代码块中定义的数据仍然活着…… 

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

uniapp分包,以及通过uni-simple-router进行分包

先说一下uniapp的直接分包方式&#xff0c;很简单&#xff1a; 配置分包信息 打开manifest.json源码视图&#xff0c;添加 “optimization”:{“subPackages”:true} 开启分包优化 我们在根目录下创建一个pagesA文件夹&#xff0c;用来放置需要分包的页面 然后配置路由 运行到…

开源啦!一键部署免费使用!Kubernetes上直接运行大数据平台!

市场上首个K8s上的大数据平台&#xff0c;开源啦&#xff01; 智领云自主研发的首个 完全基于Kubernetes的容器化大数据平台 Kubernetes Data Platform (简称KDP) 开源啦&#x1f680;&#x1f680; 开发者只要准备好命令行工具&#xff0c;一键部署 Hadoop&#xff0c;Hi…

【论文笔记】Language Models are Few-Shot Learners B部分

Language Models are Few-Shot Learners B 部分 回顾一下第一代 GPT-1 &#xff1a; 设计思路是 “海量无标记文本进行无监督预训练少量有标签文本有监督微调” 范式&#xff1b;模型架构是基于 Transformer 的叠加解码器&#xff08;掩码自注意力机制、残差、Layernorm&#…

【win10相关】更新后出现未连接到互联网的问题及解决

问题背景 在win10更新完系统之后&#xff0c;第二天电脑开机后&#xff0c;发现无法上网&#xff0c;尝试打开百度&#xff0c;但是出现以下图片&#xff1a; 经过检查&#xff0c;发现手机是可以上网的&#xff0c;说明网络本身并没有问题&#xff0c;对防火墙进行了一些设置…

采用前后端分离Vue,Ant-Design技术开发的(手麻系统成品源码)适用于三甲医院

开发环境 技术架构&#xff1a;前后端分离 开发语言&#xff1a;C#.net6.0 开发工具&#xff1a;vs2022,vscode 前端框架&#xff1a;Vue,Ant-Design 后端框架&#xff1a;百小僧开源框架 数 据 库&#xff1a;sqlserver2019 系统特性 麻zui、护理、PACU等围术期业务全覆…

【机器学习】集成学习---Bagging之随机森林(RF)

【机器学习】集成学习---Bagging之随机森林&#xff08;RF&#xff09; 一、引言1. 简要介绍集成学习的概念及其在机器学习领域的重要性。2. 引出随机森林作为Bagging算法的一个典型应用。 二、随机森林原理1. Bagging算法的基本思想2. 随机森林的构造3. 随机森林的工作机制 三…

3. uniapp开发工具的一些事

前言 新的一天&#xff0c;又要开始卷起来了&#xff0c;开发程序开发当前离不开开发工具&#xff0c;一个好的开发工具办事起来那必然是事倍功半的...本文主要分享了关于uniapp里开发工具的一些事~ 概述 阅读时间&#xff1a;约5&#xff5e;7分钟&#xff1b; 本文重点&am…

Web程序设计-实验04 JavaScript对象

题目 【实验主题】 个人所得税计算 【实验任务】 1、根据【任务提示】和【参考资源】材料&#xff0c;自学2012版月工资、年终奖个人所得税计算规则。 2、新建 .js文件&#xff0c;以JSON格式定义个人所得税对象。 其中属性涉及三个层次&#xff1a; 1&#xff09;第一层…

03-MVC执行流程-参数解析与Model

重要组件 准备Model&#xff0c;Controller Configuration public class WebConfig {ControllerAdvicestatic class MyControllerAdvice {ModelAttribute("b")public String bar() {return "bar";}}Controllerstatic class Controller1 {ResponseStatus(H…

CUDA的基础知识

文章目录 数据精度CUDA概念线程&线程块&线程网络&计算核心GPU规格参数内存 GPU并行方式数据并行流水并行张量并行混合专家系统 数据精度 FP32 是单精度浮点数&#xff0c;用8bit 表示指数&#xff0c;23bit 表示小数&#xff1b;FP16 是半精度浮点数&#xff0c;用…

SpringBoot常用注解与注意事项

Spring Boot 是一个用于快速开发、运行和管理 Spring 应用程序的框架。它大量使用了注解&#xff08;Annotations&#xff09;来简化配置和开发流程。 以下是一些 Spring Boot 中常用的注解及其注意事项&#xff1a; 1.常用注解 SpringBootApplication 这是一个组合注解&#…

OpenHarmony 项目实战:智能体重秤

一、简介 本 demo 基于 OpenHarmony3.1Beta 版本开发&#xff0c;该样例能够接入数字管家应用&#xff0c;通过数字管家应用监测体重秤上报数据&#xff0c;获得当前测量到的体重&#xff0c;身高&#xff0c;并在应用端形成一段时间内记录的体重值&#xff0c;以折线图的形式…

vivado Aurora 8B/10B IP核(4)-数据流接口(Streaming Interface)

Streaming 接口 Transmitting and Receiving Data&#xff08;发送和接收数据&#xff09; 流式接口允许将Aurora 8B/10B通道用作管道。 初始化后&#xff0c;通道始终可用于写入&#xff0c;除非发送时 钟补偿序列。 核心数据传输符合AXI4-Stream协议。当s_axi_tx_tvalid被取…

OpenHarmony 实战开发——分布式购物车案例展示~

简介 分布式购物车demo 模拟的是我们购物时参加满减活动&#xff0c;进行拼单的场景&#xff1b;实现两人拼单时&#xff0c;其他一人添加商品到购物车&#xff0c;另外一人购物车列表能同步更新&#xff0c;且在购物车列表页面结算时&#xff0c;某一人结算对方也能实时知道结…

基于单片机的多功能电子万年历系统

摘要:该题目要求学生综合运用单片机原理、低频电子线路、数字电路与逻辑设计等相关知识,设计完成多功能电子万年历系统。通过完成设计任务,使学生掌握单片机设计开发的基本流程,增强学生动手实践能力,培养学生分析和解决实际问题的能力,为后续课程的学习和工作打下良好基础。 关…

特征的前期融合与后期融合在召回、粗排、精排应用

前期融合&#xff1a;先对所有特征做concat&#xff0c;再输入DNN&#xff0c;一般常见于精排模型 特点&#xff1a;线上推理代价大&#xff0c;若有n个候选item需要做n次模型计算 后期融合&#xff1a;把用户和物品特征分别输入不同的神经网络&#xff0c;不对用户和物品做融…

基于Springboot的玩具租赁系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的玩具租赁系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

多用户商城系统哪个好,2024多用户商城系统这样选

在2024年选择适合的多用户商城系统是一项至关重要的决策&#xff0c;因为一个优秀的商城系统不仅可以提升用户体验&#xff0c;还能够帮助企业实现业务目标并取得长期成功。然而&#xff0c;在众多的选择中挑选出最适合的一个并不容易&#xff0c;需要综合考虑各种因素&#xf…

static page 项目

static page 项目 作者&#xff1a;不染心 博客地址&#xff1a;https://blog.csdn.net/qq_38234785 源码地址&#xff1a;https://mbd.pub/o/bread/ZpWVlJps 未经允许&#xff0c;不得转载 文档版本v1&#xff0c;还没写完持续更新 一、引言 1. 软件概述和背景 本软件是…

Python-软件设计-“帮助”小孩子自我行为(电脑端看短视频)约束

目录 前言一、方式一&#xff1a;网站访问拦截二、方式二&#xff1a;SW(电脑软件简称)启动拦截三、使用代码的方式将方式一和方式二结合成自动化程序部署四、其他拓展知识1.程序打包2、开机自启文件夹 五、报错的解决方式1、打包成软件后&#xff0c;运行那个软件时不执行或报…