C++ 对象的生存期

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

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具有静态生存期,与程序运行期相同之外,其他变量及对象都具有动态生存期。

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

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

相关文章

城市内涝 | 复杂城市排水管网系统快速建模、管网水力性能专题图制作、城市内涝一维二维耦合模拟、海绵城市关键控制指标计算

随着计算机的广泛应用和各类模型软件的发展&#xff0c;将排水系统模型作为城市洪灾评价与防治的技术手段已经成为防洪防灾的重要技术途径。本次培训将聚焦于综合利用GIS及CAD等工具高效地进行大规模城市排水系统水力模型的建立&#xff0c;利用SWMM实现排水系统水力模拟。讲解…

微信小程序(van-tabs) 去除横向滚动条样式(附加源码解决方案+报错图)

问题描述 今天第一次接触vant组件库。 ant官网地址适用于Vue3 支持Vue2、Vue3、微信小程序等 我在使用van-tabs组件时遇到了一个问题&#xff0c;如下图所示&#xff1a; 从图片上可以看到有个灰色的横向滚动条&#xff0c;一开始领导给我说这个问题&#xff0c;我反反复复都…

mybatisJava对象、list和json转换

1. 参考mybatis-plus mybatis Java对象、list和json转换 网上好多不靠谱&#xff0c;参考mybatis-plus中TableField&#xff0c;mybatis中自定义实现 这样不需要对象中属性字符串接收&#xff0c;保存到表中&#xff0c;都是转义字符&#xff0c;使用时还要手动转换为对象或者…

IOS + Appium自动化教程

前言 项目闲置下来了&#xff0c;终于抽空有时间搞自动化了&#xff0c;看了下网上的教程基本通篇都是android自动化的介绍 &#xff0c;ios自动化方面的内容网上简介的少之可怜。由于本人对ios自动化也是第一次做&#xff0c;甚至对苹果电脑的使用都不太熟悉&#xff0c;花了大…

51:电机(ULN2003D)

1:介绍 我们51单片机使用的是直流电机 直流电机是一种将电能转换为机械能的装置。一般的直流电机有两个电极&#xff0c;当电极正接时&#xff0c;电机正转&#xff0c;当电极反接时&#xff0c;电机反转 直流电机主要由永磁体&#xff08;定子&#xff09;、线圈&#xff08;转…

功率放大器的种类有哪三种类型

功率放大器是一种能将输入信号转换为更高功率输出的电子设备。在电子工程和音频领域中&#xff0c;功率放大器通常被分为三种类型&#xff1a;A类、B类和AB类。下面安泰电子将详细介绍这三种类型的功率放大器及其特点。 A类功率放大器 A类功率放大器是一种基本的线性功率放大器…

C++内存管理(动态内存开辟)

我们在C语言当中想要使用堆区的空间的时候就需要使用malloc函数进行手动的申请&#xff0c;但是我们在申请的时候需要手动进行计算&#xff0c;经过计算之后还需要进行判空操作&#xff0c;并且还不能进行任意值的初始化。这一切看起来在学习完C当中的动态开辟之前显得很正常&a…

Pytorch个人学习记录总结 10

目录 优化器 优化器 官方文档地址&#xff1a;torch.optimhttps://pytorch.org/docs/stable/optim.html Debug过程中查看的grad所在的位置&#xff1a; model --> Protected Atributes --> _modules --> ‘model’ --> Protected Atributes --> _modules -…

【PostgreSQL】系列之 一 CentOS 7安装PGSQL15版本(一)

目录 一、何为PostgreSQL&#xff1f; 二、PostgreSQL安装 2.1安装依赖 2.2 执行安装 2.3 数据库初始化 2.4 配置环境变量 2.5 创建数据库 2.6 配置远程 2.7 测试远程 三、常用命令 四、用户创建和数据库权限 一、何为PostgreSQL&#xff1f; PostgreSQL是以加州大学…

MacOS Monterey VM Install ESXi to 7 U2

一、MacOS Monterey ISO 准备 1.1 下载macOS Monterey 下载&#x1f517;链接 一定是 ISO 格式的&#xff0c;其他格式不适用&#xff1a; https://www.mediafire.com/file/4fcx0aeoehmbnmp/macOSMontereybyTechrechard.com.iso/file 1.2 将 Monterey ISO 文件上传到数据…

shell清理redis模糊匹配的多个key

#!/bin/bash# 定义Redis服务器地址和端口 REDIS_HOST"localhost" REDIS_PORT6380# 获取匹配键的数量 function get_matching_keys() {local key_pattern"$1"redis-cli -h $REDIS_HOST -p $REDIS_PORT -n 0 KEYS "$key_pattern" }# 删除匹配的键 …

java+springboot+mysql企业邮件管理系统

项目介绍&#xff1a; 使用javaspringbootmysql开发的企业邮件管理系统&#xff0c;系统包含超级管理员、管理员、员工角色&#xff0c;功能如下&#xff1a; 超级管理员&#xff1a;管理员管理&#xff1b;员工管理&#xff1b;反馈管理&#xff1b;系统公告&#xff1b;个人…

【Linux学习】日积月累——进程控制

一、进程创建 1.1 fork函数的认识 #include<unistd.h> pid_t fork(void); 返回值&#xff1a;自进程返回0&#xff0c;父进程返回子进程PID&#xff0c;出错返回-1进程调用fork&#xff0c;当控制转移到内核中的fork代码后&#xff0c;内核做&#xff1a;分配新的内存块…

Linux ALSA音频工具aplay、arecord、amixer的使用方法

ALSA 是Advanced Linux Sound Architecture的缩写&#xff0c;先进的Linux音频架构&#xff0c;为Linux操作系统提供音频和MIDI功能。 aplay命令 aplay是播放命令。 rootimx6ul7d:~# aplay -h Usage: aplay [OPTION]... [FILE]...-h, --help help--version …

解决Hadoop审计日志hdfs-audit.log过大的问题

【背景】 新搭建的Hadoop环境没怎么用&#xff0c;就一个环境天天空跑&#xff0c;结果今天运维告诉我说有一台服务器磁盘超过80%了&#xff0c;真是太奇怪了&#xff0c;平台上就跑了几个spark测试程序&#xff0c;哪来的数据呢&#xff1f; 【问题调查】 既然是磁盘写满了&…

浅谈微服务异步解决方案

导言 异步是一种设计思想&#xff0c;不是设计目的&#xff0c;因此不要为了异步而异步&#xff0c;要有所为&#xff0c;有所不为。 异步不是『银弹』&#xff0c; 避免试图套用一个『异步框架』解决所有问题&#xff0c; 需要根据不同的业务特点或要求&#xff0c;选择合适的…

VSCode自定义闪烁光标

打开VSCode 组合键ctrlshiftp搜索"settings.json",打开User Settings 加上这一句 "editor.cursorStyle": "block","workbench.colorCustomizations": {"editorCursor.foreground": "#5c8fb1","terminalCurs…

IDEA中Git面板操作介绍 变基、合并、提取、拉取、签出

IDEA中Git面板操作介绍 变基、合并、提取、拉取、签出 面板介绍 变基、合并 提取、拉取 签出、Checkout 面板介绍 如图&#xff0c;在IDEA的Git面板中&#xff0c;仓库会分为本地仓库和远程仓库&#xff0c;代码仓库里面放的是各个分支。 分支前面的书签&#x1f516;标志…

JavaScript高级——ES6基础入门

目录 前言let 和 const块级作用域模板字符串一.模板字符串是什么二.模板字符串的注意事项三. 模板字符串的应用 箭头函数一.箭头函数是什么二.普通函数与箭头函数的转换三.this指向1. 全局作用域中的 this 指向2. 一般函数&#xff08;非箭头函数&#xff09;中的this指向3.箭头…

MongoDB文档--基本安装-linux安装(mongodb环境搭建)-docker安装(挂载数据卷)-以及详细版本对比

阿丹&#xff1a; 前面了解了mongodb的一些基本概念。本节文章对安装mongodb进行讲解以及汇总。 官网教程如下&#xff1a; 安装 MongoDB - MongoDB-CN-Manual 版本特性 下面是各个版本的选择请在安装以及选择版本的时候参考一下&#xff1a; MongoDB 2.x 版本&#xff1a…