6.1 对象的构造与析构

类和对象中-构造与析构 摘要: 本文详细讲解了C++中两个重要的默认成员函数——构造函数与析构函数。 阅读详情

Q1:对象的构造函数与析构函数的分布

• 对象在被创建时就会调用其构造函数 ,若在一个区段中有一个以上的离开点,则析构函数必须放在每个离开点前

Eg:

    {
        Point point;
        //构造函数调用

        switch(int(point.x))
        {
            case -1 : 
                //析构函数
                return;
            case 0 :
                //析构函数
                return;
            case 1 : 
                //析构函数
                return;
            default:
                //析构函数
                return;
        }
        //析构函数(尽管程序不会运行到这里,但在对象的生命结束期末尾也会调用析构函数)
    }

• 把对象尽可能的放置在使用它的程序区段附近,可以节省非必要的对象产生操作和销毁操作



Q2:全局对象

• 全局对象如果有构造函数与析构函数的话,称这个全局对象需要静态初始化操作和内存释放操作

• C++中所有的全局变量都放置在程序的数据段中,若显示给定一个值,则对象以该值作为初值,否则对象所配置到的内存内容为0

• 全局类对象在编译器被放置在数据段中且内容为0,构造函数直到程序启动时才会实施

• 全局对象的Munch策略,实现在程序开始时对全局对象进行初始化,在程序结束前调用对象的析构函数

  1. 为每一个需要静态初始化的文件产生一个_sti()函数,内含必要的构造函数调用操作或 inline expansions

  2. 在每一个需要静态的内存释放操作的文件中产生一个_std()函数,内含必要的析构函数的调用操作

  3. 提供一组运行时库”munch”函数:

    1) 一个_main()函数(用以调用可执行文件中所有的_sti()函数)
    2) 一个exit()函数(用以调用可执行文件中所有的_std()函数)

• 收集一个程序中各个对象的_sti()函数与_std()函数

  1. 分析符号表格的方法

        a) 使用nm列出对象文件的符号表格项目
    
        b) 使用 munch 程序分析符号表格中的名称,搜索以_sti或_std开头的名称
    
        c) 把这些函数名称加到一个sti()函数和std()函数的跳离表格中,并将这个更表格写到一个小的 program test 文件中 
    
        d) CC命令被激活,编译这个内含表格的文件,重新连接整个可执行文件
    
        e) _main()函数与exit()函数在各个表格上走访一遍,轮流调用每一个项目        
    
  2. 基于特定平台的C++编译器的情况下,定义不同的目的文件格式,以支持静态初始化与内存释放操作




Q3:局部静态对象

• 局部静态对象的构造函数与虚构函数在程序的生命周期中只会被调用一次,尽管其所在函数可能被调用多次

• 保护局部静态对象的初始化操作(确保在整个生命周期中只执行一次)

• 导入一个临时对象以保护静态局部变量的初始化操作

• 第一次处理其所在函数时,该临时对象被评估为 false,于是静态局部对象构造函数被调用,然后将临时对象改为 true,之后再处理该函数时,不会再调用静态局部对象的构造函数

• 保护局部静态对象的析构操作(确保只在程序结束前进行销毁)

• 有条件的施行静态局部对象的构造函数:仅在静态局部对象已经被构造了的情况下,才在最后施行析构操作。(可判断保护构造函数的临时对象是否为true)

• 一个问题:不可以在静态内存释放函数中存取静态局部对象(因为该对象是局部的)
• 解决办法:可以取出该局部对象的地址(这是因为该对象是静态对象,因此会被存储在放置全局对象的数据段中,因此,取出的局部对象的地址不会失效(**特别注意:当且仅当为静态对象才行))

Eg:

        const Matrix & identity()
        {
            static Matrix mat_identity;
            //…
            return mat_identity;
        }

该函数将被扩展为以下形式:(加入了构造函数保护对象)

        static struct Matrix * __0_F3 = 0;      //临时对象

        //C++中的引用在C中是以指针来代替的

        struct Matrix * identity_Fv()
        {
            static struct Matrix __lmat_identity;

            //如果临时性的保护对象已经设定,那就什么也不做;
            //否则将调用构造函数(__ct__6MatrixFv),设定保护对象,使其指向目标对象(为销毁对象做准备)

            __0_F3 ? 0 : (__ct__6MatrixFv)(&__lmat_identity),(__0_F3 = (&__lmat_identity)));

            //…
        }

该静态局部对象的析构函数将在静态内存释放函数中有条件的调用:

        char __std__stat_0_c_j()
        {
            __0_F3 ? __dt_6MatrixFv(__0_F3,2) : 0;

            //…
        }



Q4:对象数组

• 假设有以下数组定义:

Point knots[10];

• 若 Point 即没有定义一个构造函数也没有定义一个析构函数,则该操作的工作与建立一个“内建类型所组成的数组”相同,只需要分配足够内存来存储10个连续的Point元素即可

• 若 Point 定义了构造函数或析构函数,则构造函数与析构函数必须轮流施行于每一个元素之上

• cfront 中,使用一个命名为vec_new()的函数,产生出以类对象构造而成的数组(该类对象没有虚基类),用另一个命名为vec_vnew()的函数来处理内含虚基类的类对象数组

• 关于vec_new()

    • 原型:void * vec_new(
                            void * array,               //数组起始地址
                            size_t elem_size,           //每一个类对象的打下
                            int elem_coutn,                                //数组中元素的个数
                            void (*constructor)(void*),           //构造函数的指针
                            void(*destructor)(void*,char)  //析构函数的指针
                            )
    • 若array持有的不是数组的地址,就是0。若是0,则数组将通过应用程序的 new 运算符,动态配置于对中。

• Eg:上述 Point 数组的定义操作,被编译器转换为:

            Point knots[10];
            vec_new(&knots,sizeof(Point),10,&Point::Point,0);

• 当对象数组的生命结束时,其析构函数也必须实行于每个对象上,此时类似的 vec_delete()与vec_vdelete()函数来完成析构函数的调用

• 当程序员提供一个或多个明显的初值给一个由类对象组成的数组时,对于明显获得初始的元素,vec_new()不再必要,对未获得初始值的元素,仍旧调用vec_new()

Eg:

        Point knots[10] = { Point(), Point(1.0,1.0,0.5),-1};

编译器将其转换为如下:

        Point knots[10];

        //显示的初始化前三个元素
        Point::Point(&knots[0]);
        Point::Point(&knots[1],1.0,1.0,0.5);
        Point::Point(&knots[2],-1,0,0);

        //仍旧以 vec_new() 调用构造函数初始化后七个元素
        vec_new(&knots+3,sizeof(Point),7,&Point::Point,0);



Q5:默认构造函数和数组

• 不能在程序中取出构造函数的地址,对vec_new()函数而言,经由一个指针来启动构造函数,将无法存取默认参数值

• cfront的解决办法:产生一个内部的stub constructor,该构造函数没有参数。但在其内部调用由程序员提供的构造函数,并将参数值显示的指定过去

• 对于cfront而言,将有两个没有参数的构造函数,一个默认构造函数(带默认参数值),一个合成的stub constructor。当时只有当类对象数组真正被产生出来时,stub实例才会被产生并调用

Eg:

        class complex
        {
            complex(double = 0.0,double = 0.0);
            //…
        };

当程序员定义:complex c_array[10];
编译器需要调用: vec_new(&c_array,sizeof(complex),10,&complex::complex,0); //将无法获得默认参数
因此,合成以下 stub constructor

        complex::complex()
        {
            complex(0.0,0.0);
        }
C++全局构造与析构底层实现 *前一阵儿,被施老师问到C++全局变量是如何构造和析构的。。。?之前看书的时候好像忽略了这个点。。现在补上。。。→_→* 阅读详情

相关推荐

学生类构造函数

定义学生类,构造函数 foreach循环计算学生的平均分

PTA实验题:6-7 学生类的构造与析构 (10 分)

类定义: 定义一个学生类Student,使得main()函数能够得到指定的输出结果 main()函数如下: /* 请在这里填写答案 */ int main() {Student stud1(10010,"Wang_li",'f'); stud1.display(); Student stud2(10011,"Zhang_fun",'m'); stud2.display(); return 0; } 输入样例: 无 输出样例: 在这里给出相应的输出。例如: Construct

巧克力曲奇饼冰淇淋的博客 5262

VMware桥接模式实战:用手机热点给Linux虚拟机共享网络(附WiFi适配技巧)

本文详细介绍了在移动办公场景下,如何为VMware中的Linux虚拟机配置桥接模式,以通过手机热点共享网络。文章深入解析了桥接模式在无线环境下的工作原理,提供了从主机端准备、VMware设置到Linux虚拟机内部配置的完整实战步骤,并针对手机热点的特殊性,分享了MTU优化、DNS配置及常见网络问题的诊断与解决方案,帮助用户实现稳定高效的移动虚拟化办公。

2y3u4i5o6p的博客 1194

【C++】从入门到精通第二弹——类的构造与析构函数

构造函数和析构函数是两个特殊的成员函数,都没有返回值,构造函数名和类名相同,析构函数名只是在类名前加上 ~ 构造函数主要用来在创建对象时给对象中的数据成员赋值,主要目的是初始化对象, 析构函数的功能与构造函数正好相反,析构函数是用来释放对象的,再删出对象前,对对象进行清理工作

小洁洁 441

微信公众号开发实战:如何高效推送模板消息(附完整代码示例)

本文详细解析了微信公众号开发中模板消息推送的核心流程与实战技巧。文章从OpenID获取、模板申请、Access Token缓存管理到完整PHP代码实现,逐步拆解了高效推送模板消息的关键步骤,并提供了可直接复用的代码示例,帮助开发者快速集成这一提升用户体验的重要功能。

weixin_29009971的博客 793

基于STM32的Keil5代码自动补全设置操作指南

掌握Keil5代码自动补全设置技巧,提升STM32开发效率。通过合理配置编辑器选项,实现智能提示与语法补全,让嵌入式编程更流畅,尤其适合使用keil5代码自动补全设置的开发者快速上手。

weixin_32287387的博客 762

【C++基础】第二节课 类的构造和析构

目录 1 构造函数的定义 2 构造函数初始化列表 3 默认构造函数 4 复制构造函数 5 关于构造函数的总结 6 析构函数 7 对象的动态建立与释放 8 构造函数和析构函数执行顺序 1 构造函数 1.1 类对象如何初始化 如果类的数据成员是public的权限,可以在定义对象时初始化。 class Time { public: int hour; ...

harveyhan的专栏 592

VerilogEval实战指南:从基准测试到模型微调的全流程解析

本文提供了VerilogEval实战指南,详细解析了从基准测试到模型微调的全流程。VerilogEval是一个自动化、标准化的测试框架,用于客观评估大语言模型生成Verilog硬件代码的能力。文章涵盖了环境搭建、核心机制解析、利用其生成合成数据进行模型微调的策略,以及如何将其工程化集成到自动化评估流程中,为硬件设计领域的AI应用提供了完整的方法论。

yy01234的博客 1005

类的构造和析构

基本类型重载时会自动将小类型提升到int类型,如下的程序 public class Test { public static void main(String args[]) { Test t = new Test(); t.f1(3); //默认提升为int t.f1((char)3);//进行了显示的转换,所以会调用char的函数 } void f1(char x) {

Good good study! 1804

am62x A53与R5F通信

AM62x是Ti的一款异构多核芯片。remoteproc驱动,硬编码(写死)了R5F/M4F固件的名字,这样驱动启动时,就会找硬件编码的固件,下面是其对应关系。值得注意的是,linux内核中的M4F remoteproc驱动启动M4F,而linux内核中的R5F remoreteproc驱动不启动R5F,相反,它attach到已经在boot阶段启动的R5F固件上。在/lib/firmware的真实固件名:,而我们生成的固件名如下所示,没有直接对应的,经确认,.out文件就是我们需要的,重命名后即可。

鹰之翔 1359

Allegro如何改变线宽操作指导

用Allegro做pcb设计的时候,改变走线线宽是非常常用的功能,如下图。线宽目前是12mil,需要把线宽改成15mil。如何改变线宽操作指导。

weixin_54787054的博客 4254

[c++] c++ 中的顺序(构造,析构,初始化列表,继承)

对象构造的时候,对象成员变量的初始化顺序是什么样的?派生类构造的时候,先构造基类还是先构造派生类?构造函数中的初始化列表,初始化的顺序是列表的顺序吗?析构的时候,析构的顺序是什么样的?本文通过实例代码记录上述场景下的顺序。先说结论:(1)全局对象以及静态全局对象,在 main 函数调用之前创建(2)构造时,先构造类中的成员变量,再调用构造函数(3)类中成员变量的构造顺序是变量在类中声明的顺序(4)初始化列表中,成员变量的初始化顺序也是变量在类中声明的顺序。

weixin_38184628的博客 2534

《YOLO11改进有效涨点》 专栏目录 | 目前已有100+篇内容,内含各种Head检测头、损失函数Loss、Backbone、Neck等创新点改进【持续更新】

YOLO11改进专栏目录,YOLO11改进目录

kay_545 1万+

17、对象的构造和析构

下面是cfront的输出。2)类似情况,在每一个需要静态的内存释放操作(static dealllocation)的文件中,产生一个__std()函数(译注:我想std就是static deallocation的缩写),内含必要的destructor调用操作,或是其inline expansions。3)提供一组runtime library “munch”函数:一个_main()函数(用以调用可执行文件中的所有__sti()函数),以及一个exit()函数(以类似的方式调用所有的__std()函数)。

u012750235的博客 992

【JDK】win 10 / win 11:jdk 8 下载、安装、配置、验证

win10 / win 11:JDK 最新版本下载 / 历史版本下载(jdk 8)、安装、配置系统环境变量、验证安装全详细操作教程

顾三殇 —— 博客空间(软件测试) 13万+

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

C++全局对象的构造与析构

C++全局对象构造与析构 先上代码: //simpleClass.cpp class A{ int val; public: A(int n){ val = n; } ~A(){ val = 0; } }; A a1(1); int main(){ A a2(2); return 0; } 抛出问题:局部对象a2和全局对象a1分别在何处调用构造函数和析构函数? 将上述cpp文件编译成可一致性文件: g++ -o

qq_38600065的博客 2578

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

C++的类与对象(三):构造和析构、缺省值、类对象的销毁顺序、拷贝构造(重要)

且成员变量的初始化顺序由它们在类中声明的顺序决定,而不是由构造函数初始化列表的顺序决定。

m0_73975164的博客 1328

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

锂电池充电器电路设计 里面有电路

锂电池充电器电路设计 里面有电路 3.7V升压到5V电路设计。

C++学习之对象的构造和析构

C++学习之对象的构造和析构

qq_27302885的博客 1301

第6章 执行期语义学1:对象的构造和析构

我们通过几个例子来看看一般的构造函数和析构函数是怎么安插的吧如上所示,每当一个对象被定义的时候,编译器就会显式插入一个该对象的构造函数,当该对象所在的作用为即将结束的时候,编译器就会自动为它安插一个析构函数。

qq_40178082的博客 752

C++对象构造与析构全流程

对象构造流程 1. 首先,如果有virtual base class constructors,虚基类的构造函数必须被调用,从左往右,从深往浅: ->如果有virtual base class constructor位于成员初值列,有任何显示指定的参数都应该传递过去;若没有位于初值列,而virtual base class含有一个默认构造函数,也应该调用。 ->class中的...

Innocent_code的专栏 812

C++中对象的构造与析构顺序

详解C++中对象的构造与析构顺序

2301_76197086的博客 1141

第 13 天:构造与析构的嵌入式实践 —— 管理对象生命周期的关键机制

在嵌入式 C++ 开发中,构造函数与析构函数不仅是类的语法组成部分,更是对象生命周期管理的根基。嵌入式系统往往面对资源受限、生命周期精细化要求高的场景,构造函数负责初始化资源状态,析构函数则负责清理、释放。合理地使用构造与析构,能极大提升系统的稳定性与可维护性。本篇将围绕构造/析构机制的工作原理、工程实践策略,以及嵌入式环境中的使用限制,帮助开发者构建稳健的对象管理体系。

努力分享一些人工智能、计算机视觉、影像等相关的知识干货! 1229

【C++】类和对象(三)构造与析构

1️⃣函数名和类名相同2️⃣没有返回值(不需要写)class Datepublic://函数名与类名相同 没有返回值 不用写voidDate()_year = 1;_month = 1;_day = 1;int _month;int _day;d1.Print();return 0;3️⃣对象实例化时 编译器自动调用该函数,如果没有构造函数可调,会报错。

烧鸡配油茶的博客 1595

不同作用域对象的构造析构调用时机

全局变量和全局静态变量 使用vc栈回溯发现 这里构造的栈结构 因为atexit的参数的c约定回调,而析构是thiscall,调用约定,所以内部必须包含一层E2才可以,在使用E2调用析构,而不是直接注册析构 atexit可以注册多个回调,而这些会是一个线性表,里面储存了你注册的函数地址.当main函数结束的时候会调用 1.会在ininterm里面进行初始化动作 2.会产生代理函数,这个代理函数...

qq_35426012的博客 488

Python 类的构造方法、析构方法、实例方法

1. 实例方法1.1 定义实例方法是用于访问对象实例属性的方法,语法如下:登录后复制 class 类: def 实例方法(self): self.属性1.2.3.实例方法定义在类中,它的第一个参数 self 指向调用该方法的对象,在实例方法中通过 “self.属性” 访问对象的实例属性。1.2 例...

小屁孩大帅-保密的博客 835
上一篇: C++实现线程池类
下一篇: 6.2 new 和 delete 运算符
Virtual_Func
博客等级 码龄11年 38粉丝 113原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值