C++ 对象的生存期

news2024/11/11 5:48:42

对象(包括简单变量)都有诞生和消失的时刻。对象诞生到结束的这段时间就是它的生存期。在生存期内,对象将保持它的状态(即数据成员的值),变量也将保持它的值不变,直到它们被更新为止。对象的生存期可以分为静态生存期动态生存期

1.静态生存期

如果对象的生存期与程序的运行期相同,则称它具有静态生存期。

(1)在命名空间作用域中声明的对象都具有静态生存期。比如说,全局变量。

【例1】

#include<iostream>
using namespace std;
int i = 10;//i为全局变量,具有静态生存期
int fun1(int a=i)
{
	i = a;//给i重新赋值为传给形参a的值50
	return i;
}
int fun2(int a=i)
{
	return i;
}
int main()
{
	cout << "i=" << fun1(50) << endl;//通过调用函数fun1返回变量i的值
	cout << "i=" << fun2(20) << endl;//通过调用函数fun2返回变量i的值
	cout << "i=" << i << endl;//直接输出变量i的值
	return 0;
}

运行结果及分析:
因为在fun1函数中给全局变量i重新赋值为传给形参a的值,主函数中传给fun1函数的形参为50,所以给全局变量i重新赋值为50。因此主函数中无论是调用fun2函数,还是在主函数中直接输出i的值,结果都为50。又因为变量i是全局变量,所以它生存期与程序的运行期相同,整个程序运行结束时才消失。
在这里插入图片描述
【例2】

int i = 10;//i为全局变量,具有静态生存期
int fun1(int a=i)
{
	return i;
}
int fun2(int b=i)
{
	return i;
}

int main()
{
	cout << "i=" << fun1(50) << endl;
	cout << "i=" << fun2(20) << endl;
	cout << "i=" << i << endl;
	return 0;
}

运行结果及分析:
因为函数fun1和函数fun2只是通过传参的方式返回全局变量i的值,并没有真正改变i的值,所以在主函数中无论给函数fun1和fun2传任何整型类型的参数,输出的结果都为10。因为变量i是全局变量,所以它生存期与程序的运行期相同,整个程序运行结束时才消失。
在这里插入图片描述

(2)如果要在函数内部的局部作用域中声明具有静态生存期的对象,则要关键字 static。

例如下面语句定义的变量i便是具有静态生存期的变量,也称为静态局部变量(静态变量)

int i = 10;//i为全局变量,具有静态生存期
int fun(int a)
{
	static int i = a;//i为静态局部变量,具有静态生存期(全局寿命),局部可见
	i=i+1;
	return i;
}
int main()
{
	cout << "i=" << fun(20)<<endl;//输出的是fun函数中静态变量i的值
	cout << "i=" << fun(30)+2 << endl;//输出的是fun函数中静态变量i加2的
	cout << "i=" << i << endl;//输出的是全局变量i的值
	return 0;
}

运行结果及分析:
在fun函数中,定义变量i时加了关键字static使得变量i为静态变量,所以该变量i只在调用fun函数时起作用,在fun函数之外,仍然是全局变量i在起作用,所以第一次输出i的值为21。当fun第一次返回i的值为21之后,下一次再调用fun函数时无论传参的值时多少,fun函数中的变量i的值在一开始仍然为第一次返回的值21,然后执行语句i=i+1;,i的值变为22,第二次返回i的值为22,然后主函数中第二次输出i的值的时候又给22加2,所以第二次输出i的值为24。第三次输出的i的值是全局变量i的值,所以第三次输出i的值为10。说明在函数fun中通过static定义了变量i的值并赋值之后就不可以再通过调用fun函数进行传参来修改变量i的值,且此静态变量i的值只可以在函数fun的函数体中进行修改。
在这里插入图片描述
局部作用域中静态变量的特点是:
它并不会随着每次函数调用而产生一个副本,也不会随着函数返回而失效。也就是说,当一个函数返回后,下一次调用时,该变量还会保持上一回的值,及时发生了递归调用,也不会为该变量建立新的副本,该变量会在每次调用间共享。
在定义静态变量的同时可以给它赋初值,如:static int i = 20;,这表示i会被赋予20初始化,但是并不是每次执行函数时都将i赋值为20。
【注意】在定义时未指定初值的基本类型静态生存期变量,会被赋予0初始化,而对于动态生存期变量,不指定初值意味着初值不确定。

2.动态生存期

除了上述的两种情况,其余对象都具有动态生存期。块作用域中声明的,没有用static修饰的对象是动态生存期的对象。在局部作用域中声明的具有动态生存期的对象,习惯上也称为局部生存期对象。动态生存期对象开始于程序执行到声明点时,结束于命名该标识符的作用域结束处。局部生存期对象诞生于声明点,结束于声明所在块执行完毕时。

【例1】变量的生存期于可见性

#include<iostream>
using namespace std;

int i = 1;//i为全局变量,具有静态生存期
void other()
{
	//a、b为静态局部变量,具有全局寿命,局部可见,只第一次进入函数时被初始化
	static int a = 2;
	static int b;
	int c = 10;//c为局部变量,具有动态生存期,每次进入函数时都初始化
	a += 2;
	i += 32;
	c += 5;
	cout << "other:   " << endl;
	cout << "i: " << i << "  a: " << a << "  b: " << b << "  c: " << c << endl;
	b = a;//b=4
}
int main()
{
	static int a;//a为静态局部变量,具有全局寿命,局部可见,只第一次进入函数时被初始化
	//b,c为局部变量,具有动态生存期
	int b =-10;
	int c = 0;
	cout << "main:   " << endl;
	cout << "i: " << i << "  a: " << a << "  b: " << b << "  c: " << c << endl;
	c += 8;//c=8
	other();
	cout << "main:   " << endl;
	cout << "i: " << i << "  a : " << a << "  b : " << b << "  c : " << c << endl;
	i += 10;
	other();
	return 0;
}

运行结果及分析:
在命名空间作用域中定义全局变量i,在主函数中,定义a为静态局部变量,b,c为局部变量,在other函数中定义a、b为静态局部变量,c为局部变量。
当程序从主函数开始运行,第一次输出主函数main中的i,a,b,c的值时,由于i是全局变量,所以输出1;a是静态局部变量但没有赋初值,所以输出0;b在定义时初始化为-10,所以输出-10;c在定义时初始化为0,所以输出0。**因此第一次输出主函数中的i,a,b,c的值分别为1,0,-10,0。**在主函数中第一次输出i,a,b,c的值之后,将c的值变为8。
主函数main第一次调用other函数,在other函数输出i,a,b,c的值之前,在other函数中给局部静态变量a赋初值为2,没有给局部静态变量b赋初值,所以默认为0,定义局部变量c并初始化为10。然后给静态局部变量a+2,a的值变为4,给全局变量i+32,i的值变为33,给局部变量c+5,c的值变为15,所以第一次输出other函数中的i,a,b,c的值分别为33,4,0,15。 在other函数第一次输出i,a,b,c的值之后,将a的值赋给b,b=4。
第二次输出主函数main中的i,a,b,c的值时,由于在other函数中将全局变量i的值变为了33,所以全局变量i在之后的所有程序中应用到的值都为33,a的值仍然为一开始在主函数中定义的静态局部变量a的默认值0,局部变量b的值也没有发生改变仍然为-10,由于在主函数中第一次输出i,a,b,c的值之后,将c的值变为8,所以此时主函数中c的值应为8。**因此第二次输出主函数中的i,a,b,c的值分别为33,0,-10,8。**在主函数中第二次输出i,a,b,c的值之后,给全局变量i的值加10,即33+10,此时全局变量i的值为43,且全局变量i在之后的所有程序中应用到的值都为43。
主函数第二次调用other函数,在other函数输出i,a,b,c的值之前,给静态局部变量a+2,由于第一次在other函数结束时,a的值为4,现在再给a+2,所以a的值就变为6;给全局变量i+32,由于在主函数中将全局变量i的值变为了43,所以i的值为75;局部变量c则没有改变仍然为15;由于在other函数第一次输出i,a,b,c的值之后,将a的值4赋给静态局部变量b,b=4,所以,在第二次调用other函数时,静态局部变量b的值仍然为上一次other函数结束时b的值4。因此第二次输出other函数中的i,a,b,c的值分别为75,6,4,15。
在这里插入图片描述

【例2】具有静态和动态生存期对象的时钟程序。

#include<iostream>
using namespace std;

class Clock//定义时钟类
{
public://外部接口
	Clock();
	void setTime(int newH, int newM, int newS);//3个形参均具有函数原型作用域
	void showTime();
private:
	int hour, minute, second;//私有数据成员
};

//时钟类成员函数的实现
Clock::Clock():hour(0),minute(0),second(0){}//构造函数
void Clock::setTime(int newH, int newM, int newS)//3个形参都具有局部作用域
{
	hour = newH;
	minute = newM;
	second = newS;
}

void Clock::showTime()
{
	cout << hour << ":" << minute << ":" << second << endl;
}

Clock globClock;// 声明对象globClock,具有静态生存期,命名空间作用域
//由默认构造函数初始化为0:0:0

int main()
{
	cout << "第一次输出时间为:" << endl;

	//引用具有命名空间作用域的对象globClock
	globClock.showTime();	//显示0:0:0

	globClock.setTime(8, 30, 30);//将时间设置为8:30:30

	Clock myClock(globClock);//声明具有块作用域的对象myClock
	//调用默认的拷贝构造函数,以globClock的值为初值

	cout << "第二次输出时间为:" << endl;
	myClock.showTime();//引用具有块作用域的对象myClock
	return 0;
}

运行结果及分析:
对象globClock为全局变量,具有静态生存期,命名空间作用域。在主函数中,引用对象globClock访问showTime函数时,因为globClock没有初始化,所以它由默认构造函数初始化为0:0:0,所以第一次输出的时间为0:0:0,然后全局对象globClock调用setTime函数,将时间设置为为了8:30:30,由于globClock是全局对象,所以在之后的程序中应用对象globClock的值都为8:30:30。然后定义了Clock类的局部对象myClock,并调用默认的拷贝构造函数,以对象globClock的值8:30:30初始化对象myClock,接下来引用局部对象myClock访问showTime函数时,由于局部对象myClock的值被初始化为globClock的值8:30:30,所以第二次输出的时间为8:30:30。
在这里插入图片描述
在这个程序中,包含了具有各种作用域类型的变量和对象。其中时钟类定义中函数成员setTime的三个形参具有函数原型作用域;setTime函数定义中的3个参数以及主函数中的对象myClock都具有局部作用域;时钟类的数据、函数成员具有类作用域;对象globClock具有命名空间作用域。在主函数中,这些变量、对象以及对象的公有成员都是可见的。就生存期而言,除了命名空间作用域的对象globClock具有静态生存期,与程序运行期相同之外,其他变量及对象都具有动态生存期。

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

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

相关文章

windows下安装anaconda、pycharm、cuda、cudnn、PyTorch-GPU版本

目录 一、anaconda安装及虚拟环境创建 1.anaconda的下载 2.Anaconda的安装 3.创建虚拟环境 3.1 环境启动 3.2 切换镜像源 3.3环境创建 3.4 激活环境 3.5删除环境 二、pycharm安装 1.pycharm下载 2.pycharm的安装 三、CUDA的安装 1.GPU版本和CUDA版本、cudnn版本、显卡…

布瑞特单圈绝对值旋转编码器串口数据读取

布瑞特单圈绝对值旋转编码器串口数据读取 数据手册&#xff1a;http://briter.net/col.jsp?id109 (2.1版本RS485说明书通信协议 单圈.pdf) 绝对式编码器为布瑞特BRT38-ROM16384-RT1&#xff0c;采用RS485通信。 该绝对式编码器共有5根线&#xff1a;红、黄、黑、绿、白 由…

解决 MyBatis-Plus + PostgreSQL 中的 org.postgresql.util.PSQLException 异常

&#x1f337;&#x1f341; 博主猫头虎 带您 Go to New World.✨&#x1f341; &#x1f984; 博客首页——猫头虎的博客&#x1f390; &#x1f433;《面试题大全专栏》 文章图文并茂&#x1f995;生动形象&#x1f996;简单易学&#xff01;欢迎大家来踩踩~&#x1f33a; &a…

计算机网络期末复习要点(谢希仁第8版)抱佛脚通用

熬夜苦肝4天&#xff0c;拿下&#xff01; 课本是谢希仁的计算机网络&#xff0c;第8版。 本文原创&#xff01;禁止转载。 复习建议&#xff1a;本博客不一定能涵盖你们考试的重点&#xff0c;所以不是走到穷途末路的同学还是应该多多回归课本&#xff0c;课本每章后面都有…

DRM几个重要的结构体及panel开发

一、DRM Linux下的DRM框架内容众多&#xff0c;结构复杂。本文将简单介绍下开发过程中用到的几个结构体。这几个结构体都在之前文章里面开发DRM驱动时用到的&#xff0c;未用到的暂不介绍。 DRM中的KMS包含Framebuffer、CRTC&#xff0c;ENCODER&#xff0c;CONNECTOR&#xff…

ARM处理器 指令(读写内存、状态寄存器、软中断、协处理器……)

一、数据处理指令1&#xff09;数学运算数据运算指令的格式数据搬移指令立即数伪指令加法指令带进位的加法指令减法指令带借位的减法指令逆向加法指令乘法指令数据运算指令的扩展 2&#xff09;逻辑运算按位与指令按位或指令按位异或指令左移指令右移指令位清零指令 3&#xff…

弱监督语义分割伪标签可视化(把单通道灰度图转为voc格式语义分割标签的彩色形式)

一、目的 以图片2007_001960为例&#xff0c;voc数据集中的原图和对应的语义分割标签分别如下&#xff1a; 图1 图2 图像级标签WSSS任务第一阶段最后生成的pseudo mask如下&#xff1a; 图3 我们的…

【100天精通python】Day22:字符串常用操作大全

目录 专栏导读 一、 字符串常用操作 1 拼接字符串 2 计算字符串长度 3 截取字符串 4 分割合并字符串 5 检索字符串 6 字母的大小写转换 7 去除字符串的空格和特殊字符 8 格式化字符串 二 、字符串编码转换 2.1 使用encode()方法编码 2.2 使用decoder()方法编码 专栏…

深度学习笔记-暂退法(Drop out)

背景 在机器学习的模型中&#xff0c;如果模型的参数太多&#xff0c;而训练样本又太少&#xff0c;训练出来的模型很容易产生过拟合的现象。在训练神经网络的时候经常会遇到过拟合的问题&#xff0c;过拟合具体表现在&#xff1a;模型在训练数据上损失函数较小&#xff0c;预…

Grandle安装配置(8.2.1)-windows环境

一、官网地址 https://gradle.org/releases/ 下载链接&#xff1a; https://downloads.gradle.org/distributions/gradle-8.2.1-bin.zip 下载后解压到指定文件夹,实例安装目录为&#xff1a; D:\ProgramFiles\gradle-8.2.1 二、配置环境变量 示例中配置的目录为&#xff1a…

二十一章:PUZZLE-CAM:通过匹配局部和全局特征来改进定位

0.摘要 弱监督语义分割&#xff08;WSSS&#xff09;被引入来缩小从像素级监督到图像级监督的语义分割性能差距。大多数先进的方法是基于类激活图&#xff08;CAM&#xff09;来生成伪标签以训练分割网络。WSSS的主要局限性在于从使用图像分类器的CAM生成伪标签的过程主要集中在…

【测试设计】基于正交法的测试用例设计工具--PICT

目录 前言 下载安装 用例生成 使用示例 具体操作&#xff1a; 资料获取方法 前言 我们都知道成对组合覆盖是一种非常有效的测试用例设计方法&#xff0c;但是实际工作过程中当成对组合量太大&#xff0c;我们往往很难做到有效的用例覆盖。 PICT是微软公司出品的一款成对…

spark-sql数据重复之File Output Committer问题

前言 我们先来回顾下之前介绍过的三种Committer&#xff1a;FileOutputCommitter V1、FileOutputCommitter V2、S3A Committer&#xff0c;其基本代表了整体的演进趋势。 核心代码讲解详细参照&#xff1a;Spark CommitCoordinator 保证数据一致性 OutputCommitter commitTask…

集群部署dolphinscheduler踩坑

本文主要总结一下最新版dolphinscheduler3.1.5的安装过程中遇到的坑。 dolphinscheduler启动报错 Exception in thread "Master-Server" org.springframework.beans.factory.BeanCreationException: Error creating bean with name masterServer: Invocation of in…

先进先出法与加权平均法的比较

加权平均法 加权平均的成本核算方法在计算销货成本和期末库存价值时使用每个库存物料的平均成本。企业将使用以下公式计算每个库存单位&#xff08;在特定会计期间内&#xff09;的平均成本&#xff1a; 平均库存成本 &#xff08;所有采购商品的总成本&#xff09;/&#xff…

Matlab Optimization Toolbox中的遗传算法工具包(GA)

matlab optimization 中使用了GA求解器 默认的是小于等于 找到GA 工具包 找到 APP选择 Optimization Tool 选择Solver ga - Genetic Algorithm 应用GA solver 定义适应度函数(Fitness function)与问题约束(Constraints) example one 优化函数 sin(x) 2 * cos(x)极其重要的…

【原创】IPTVC2实现方案(文末有demo)

前言: 名词解释: IPTVC2, 全称: 央视国际节目定价发布接口规范,标准版本当前最新为2.7.12 附赠资源链接&#xff0c;侵删:规范 规范中提供的样例&#xff0c;实现基于axis1.4(2006的时代宠物) 基于axis1版本的实现参考: Spring boot 集成Axis1.4 &#xff0c;使用wsdd文件发…

C语言每日一题:12《数据结构》相交链表。

题目&#xff1a; 题目链接 思路一&#xff1a; 1.如果最后一个节点相同说明一定有交点。 2.使用两个循环获取一下长度&#xff0c;同时可以获取到尾节点。 3。注意初始化lenA和lenB为1&#xff0c;判断下一个节点是空是可以保留尾节点的。长度会少一个&#xff0c;尾节点没有…

【C++修炼之路】多态

&#x1f451;作者主页&#xff1a;安 度 因 &#x1f3e0;学习社区&#xff1a;StackFrame &#x1f4d6;专栏链接&#xff1a;C修炼之路 文章目录 一、概念二、定义和实现1、虚函数2、虚函数的重写3、多态的构成条件4、重写的例外5、C11 override 和 final6、不能被继承的类7…

RxJava异步编程初探

RxJava 其实就是提供一套异步编程的 API&#xff0c;这套 API 是基于观察者模式的&#xff0c;而且是链式调用的&#xff0c;所以使用 RxJava 编写的代码的逻辑会非常简洁。 RxJava 有以下三个基本的元素&#xff1a; 被观察者&#xff08;Observable&#xff09;观察者&…