P28 C++ 对象的生存周期(栈的作用域生存周期)

news2024/9/24 7:25:42

前言

本期的主题是栈作用域中对象的生存期,通俗来讲,就是讨论对象是如何在栈上生存的。

这章内容整体分为两部分。

  1. 第一部分是,你必须理解栈上的东西是如何存在的,这样你才能真正写出能正常工作的代码。
  2. 第二部分是,一旦你知道了它是如何运作的,那要如何利用好它,做你想做的事情,能想出一些聪明的方法来做一些事情。

首先我们先要了解栈的概念。

栈是一种数据结构,你可以在上面堆叠一些东西。

假设你的桌子上有一堆书,为了访问中间的一个,你得先把上面的前几个拿掉,然后找到中间那本书,(当然现实世界中,你可以直接把书抽出来,但这不是栈在编程中的工作方式)。

所以每次我们在 C++ 中进入一个作用域时,我们是在 push 栈帧,但它不一定非得是将数据推进(push)一个栈帧,你可以把它想成是把一本书放在书堆上,在此作用域下(这本书内)声明的变量,就像是在书中写东西,一旦作用域结束,将这本书从书堆中拿出来,然后扔掉,那么在书中申明的每一个基于栈的变量,以及你在书中栈里创造的所有对象就都消失了。

这样有好处也有坏处,但是如果你知道你自己在做什么,百分百是有好处的。接下来一起来看一些例子,了解一下这一切是如何结合在一起的以及这一切是如何运作的。

01 什么是作用域。

作用域有很多使用场景。比如函数作用域,类作用域,比如 if 语句作用域,或者是 for 循环、while 循环作用域,甚至是空作用域。

我们来完善一个类的例子来说明。

02 在栈中创建对象

#include <iostream>

class Demo
{
public:
    Demo()
    {
        std::cout << "构造函数" << std::endl;
    }
    ~Demo()
    {
        std::cout << "析构函数" << std::endl;
    }

};

int main()
{
    Demo demo;

    return 0;
}

 这是一个简单的 Demo 类,包括构造函数和析构函数。在下面的空作用域中声明了一个 Demo ,这样写,就不是将它创建在堆上,而是创建在栈上,这将调用默认构造函数,

在main函数设置断点调试一下。

运行一步后,可以看到 "构造函数" 被打印到控制台,到了作用域的最后 },再运行一步,可以看到 "析构函数" ,意味着正在摧毁 Demo类,这部分内存已经被释放了。

03 在堆中创建对象 

怎么在堆中创建对象呢?

很简单,加*和加new关键字 

而如果改为堆分配,则是这样的效果。

断点调试一下

可以看到 "构造函数!" 后程序直接跳过了作用域的 } 这一行,并没有输出 "析构函数" ,Demp永远不会被销毁(当然,当应用程序终止时,操作系统会清除这些内存)。现在你应该已经明白了基于栈的变量和基于堆的变量在对象生存期上的区别,基于栈的变量,一出作用域就被释放了,这就是本章的重点。

04 堆中创建变量的案例

现在有了这个基础后,我们来看看一些你可能会经常做的事情。

我们可能在函数中创建数组,然后返回一个 int 类型指针,我们可能会在函数中写下面这些代码。

这看起来非常合理,但是,这完全是不对的。

这样的数组并没有在堆上分配,因为没有使用 new,我们只是在栈上声明它,当返回一个指向它的指针时,它返回一个指向栈内存的指针,这个栈内存,一旦离开作用域,内存就会被清除,在使用的时候就会失败。

如果你想实现你想要的功能,有两个选择。

  • 第一,你可以在堆上分配数组,从而确保它的生存期会一直存在。
  • 第二,你可以将这里创建的数据赋值给一个在栈作用域之外存在的变量,采取传参或者其他的方式来操作数组。在这个意义上,我们只是传递一个指针,所以不会做分配这个操作。

这个错误很常见,那有没有一种方法,可以将它这个特性用于好的方面呢?

答案是肯定的,它在很多方面都非常有用,比如可以帮助我们自动化代码。

其中一件事就是作用在类的作用域,例如智能指针 smart_ptr,或是 unique_ptr,作用域指针,或者像作用域锁(scoped_lock),有很多例子,本期先不涉及。但最简单的例子可能是作用域指针。

作用域指针基本上是一个类,一个指针的包装器,在构造时用堆分配指针,然后在析构时删除指针。所以我们可以自动化这个 new 和 delete。让我们看看如何编写这样的类。

上面是一个 DemoPtr 的类,有一个 Entity 指针成员,有一个参数为 Demo指针类型的构造函数,并完成初始化,在析构函数中,调用 delete 释放成员指向的内存。

这是一个基本的作用域指针,让我们看看如何使用它。

可以看到,这里还有一个隐式转换的过程。

设置断点调试一下。

可以看到,即使我们用 new 来做堆分配,还是可以做到内存释放。

这里不好看出来,你们还是拿代码测试一下

这是一个很好的例子,其实这是 smart_ptr、unique_ptr 做的最基本的事情。

这种自动构造,自动析构这种基于栈的变量,离开作用域后会自动销毁,是非常有用的。

#include <iostream>

class Demo
{
public:
    Demo()
    {
        std::cout << "构造函数" << std::endl;
    }
    ~Demo()
    {
        std::cout << "析构函数" << std::endl;
    }

};

class DemoPrt
{
private:
    Demo* m_demo;
public:
    DemoPrt(Demo* demo) 
        : m_demo(demo)
    {

    }
    ~DemoPrt()
    {
        delete m_demo;
    }
};


int * demoarr()
{
    return NULL;
}

int main()
{
    DemoPrt d = new Demo();

    return 0;
}

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

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

相关文章

什么是AI PC:人工智能电脑?

大家好啊&#xff0c;我是董董灿。 今天在一个群聊里&#xff0c;聊到了关于 AI PC (人工智能电脑)的话题。 之前看到过关于 AI PC 的新闻&#xff0c;说的是联想集团董事长兼CEO杨元庆在一次演讲中提到了 AI PC 的概念&#xff0c;并且绘声绘色的描绘了AI PC 的发展前景。 下…

Windows系列:windows server 2003 - 组策略部署软件

通过组策略为域内用户部署&#xff08;deploy&#xff09;软件&#xff0c;可分为指派&#xff08;assign&#xff09;和发布&#xff08;publish&#xff09;。 软件指派给用户&#xff1a;用户在域内登录后&#xff0c;被“通告 advertised”给用户&#xff0c;此时仅安装了部…

链表_相交链表

//给你两个单链表的头节点 headA 和 headB &#xff0c;请你找出并返回两个单链表相交的起始节点。如果两个链表不存在相交节点&#xff0c;返回 null 。 // // 图示两个链表在节点 c1 开始相交&#xff1a; // // // // 题目数据 保证 整个链式结构中不存在环。 // // 注意…

提升技能素养,AMCAP做出合适的决策

近年来&#xff0c;智能配置投资与理财逐渐受到关注并走俏。这是一种简单快捷的智慧化理财方式&#xff0c;通过将个人和家族的闲置资金投入到低风险高流动性的产品中。 国际财富管理投资机构AMCAP集团金融分析师表示&#xff1a;智能配置投资与理财之所以持续走俏&#xff0c…

WebUI工作流插件超越ComfyUI

在AI绘画领域&#xff0c;Stable Diffsion是最受欢迎的&#xff0c;因为它是开源软件。 开源有两大优势&#xff0c;一是免费&#xff0c;二是适合折腾。 大量的开发者、爱好者投入无尽的热情&#xff0c;来推动Stable Diffsion的快速发展。 在图形界面方面&#xff0c;WebU…

Python 进阶(十二):随机数(random 模块)

《Python入门核心技术》专栏总目录・点这里 文章目录 1. 导入random库2. 常用随机数函数2.1 生成随机浮点数2.2 生成随机整数2.3 从序列中随机选择2.4 随机打乱序列3. 设置随机数种子4. 应用实例4.1 游戏开发4.2 数据分析4.3 加密与安全4.4 模拟实验5. 总结大家好,我是水滴~~ …

Linux常用命令——mv命令

文章目录 1. 简介2. 命令格式3. 主要参数4. 常见用法及示例4.1 移动文件4.2 重命名文件4.3 交互式移动文件4.4 强制移动文件4.5 移动多个文件4.6 使用通配符移动文件 5. 注意事项6. 结论 1. 简介 mv 命令在Linux系统中用于移动文件或目录&#xff0c;同时也可以用于重命名文件…

Python使用——发送Get请求,模拟http请求 进行SSH连接服务器

前言 本篇博客是python开发的使用案例博客&#xff0c;结合一些具体的案例进行阐述&#xff0c;本篇博客主要内容是使用Python发送Get请求&#xff0c;模拟http请求&#xff0c;后面可以搞个爬虫出来&#xff0c;另外就是如何使用Python进行SSH连接服务器。 其他相关的博客文…

【代码随想录】算法训练计划37

贪心 1、738. 单调递增的数字 题目&#xff1a; 输入: n 10 输出: 9 思路&#xff1a; func monotoneIncreasingDigits(n int) int {// 贪心&#xff0c;利用字符数组s : strconv.Itoa(n)ss : []byte(s)leng : len(ss)if leng < 1 {return n}for i:leng-1; i>0; i-- …

【MATLAB】异常数据识别

基于分位数的异常点识别 首先&#xff0c;给定了一个原始数据序列x。然后&#xff0c;计算了序列x的上四分位数和下四分位数&#xff0c;并根据这两个值计算了异常点的阈值。上四分位数减去1.5倍的四分位数范围得到异常值下界&#xff0c;下四分位数加上1.5倍的四分位数范围得…

虚拟数据生成_以Python为工具

生成虚拟数据_以Python为工具 生成虚拟数据技术在现实生活中具有多个重要的应用领域。它为数据隐私保护、机器学习算法开发、数据处理和可视化等方面提供了实用且有价值的解决方案。尤其是能满足定制化需求的虚拟数据&#xff0c;在预期的方向上让数据定向随机。 &#x1f339…

下载MySQL JDBC驱动的方法

说明 java代码通过JDBC访问MySQL数据库&#xff0c;需要MySQL JDBC驱动。 例如&#xff0c;下面这段代码&#xff0c;因为找不到JDBC驱动&#xff0c;所以执行会报异常&#xff1a; package com.thb;public class JDBCDemo {public static void main(String[] args) throws …

全网最最全的Jmeter接口测试:jmeter_逻辑控制器_交替控制器Jmeter(22):jmeter_逻辑控制器_交替控制器

交替控制器 该控制器包含的取样器步骤在每次循环中交替执行 交替控制器指每次运行一次时在交替控制器下的采样器只执行一个&#xff1b;如下图&#xff1a; 忽略子控制模块&#xff1a;如果勾选此项,交替控制器将子控制器像单一请求元素一样&#xff0c;一次 只允许一个请求/…

csdn最新最全面的Jmeter接口测试:jmeter_逻辑控制器_循环控制器

循环控制器 循环次数&#xff1a;设置该控制器下的请求的循环执行次数 永远&#xff1a;勾选上的话&#xff0c;会一直循环&#xff0c;即所谓死循环 注意&#xff1a;如果线程组本身已经设置了循环次数的话&#xff0c;那循环控制元件控制的子节点 的循环次数为线程组设置的…

C语言——写一个简单函数,找两个数中最大者

#include <stdio.h>int max( int a, int b ) { return a>b ? a:b; }int main() { int a, b;printf("输入两个数:\n");scanf("%d %d", &a, &b);printf("max %d\n", max(a, b));return 0; }输出结果&#xff1a;

黑洞:宇宙中最神秘的天体

黑洞&#xff1a;宇宙中最神秘的天体 一、引言 在浩瀚的宇宙中&#xff0c;有一种神秘的天体&#xff0c;它强大到连光也无法逃逸&#xff0c;这就是黑洞。自从黑洞理论被提出以来&#xff0c;它一直是物理学家和天文学家研究的焦点。尽管我们还无法直接看到黑洞&#xff0c;…

六:Day01_Spring Boot01

一、Spring Boot简介 1. 概念简介 Spring Boot是Spring公司的一个顶级项目&#xff0c;和Spring Framework是一个级别的。 Spring Boot实际上是利用Spring Framework 4 自动配置特性完成。编写项目时不需要编写xml文件。 2. 启动器介绍 Spring Boot的启动器实际上就是一个依赖…

CMA、CNAS资质对于第三方软件检测公司意味着什么?

软件企业在了解软件检测时&#xff0c;会常常看到CMA、CNAS字样&#xff0c;那么作为软件行业内重要的合作伙伴第三方软件检测公司来说&#xff0c;CMA、CNAS资质分别是什么?又有什么意义呢? 1、CMA   CMA是中国计量认证的英文简称&#xff0c;是由省级以上人民政府计量行…

电商营销场景的RocketMQ实战01-RocketMQ原理

架构图 Broker主从架构与集群模式 RocketMQ原理深入剖析 Broker主从架构原理 HAConnection与HAClient Broker基于raft协议的主从架构 Consumer运行原理 基础知识 001_RocketMQ架构设计与运行流程分析 RocketMQ这一块&#xff0c;非常关键的一个重要的技术&#xff0c;面试的时候…

操作系统--中断异常

操作系统第一章易错总结 1.操作系统的功能 ⭐ 编译器是操作系统的上层软件&#xff0c;不是操作系统需要提供的功能。 ⭐注意&#xff1a; 1.批处理的主要缺点是缺乏交互性 2.输入/输出指令需要中断操作&#xff0c;中断必须在核心态下执行 3.多道性是为了提高系统利用率和…