C++ 析构函数

析构函数的初学 一.什么是析构函数 1.名字和类名相同,在前面加‘~’,没有参数和返回值,一个类最多只能有一个析构函数 2.析构函数对象消亡时即自动被调用。可以定义析构函数来在对象消亡前做善后工作,比 如释放分配的空间等 3.如果定义类时没写析构函数,则编译器自动生成缺省析构函数。缺省析构函数什么也不做 #include<iostream> using namespace std; class A { public: A() { cout&lt... 阅读详情

C++ 析构函数

我使用的继承开发环境: Visual Studio 2010


设计一个类时,如何写析构函数?
析构函数如果我们不写的话,C++ 会帮我们自动的合成一个,就是说:C++ 会自动的帮我们写一个析构函数。很多时候,自动生成的析构函数可以很好的工作,但是一些重要的事迹,就必须我们自己去写析构函数。
析构函数和构造函数是一对。构造函数用于创建对象,而析构函数是用来撤销对象。简单的说:一个对象出生的时候,使用构造函数,死掉的时候,使用析构函数。

下面我们来做一个例子,看看:

#include <iostream>
#include <string>

using namespace std;

class NoName{
public:
    NoName():pstring(new std::string), i(0), d(0){}
private:
    std::string * pstring;
    int i;
    double d;
};

int main(){

    return 0;
}

像上面这个 NoName 类这样的设计,类里面有一个成员变量是指针(std::string *pstring) ,那么在构造函数里我们使用 new 创建了对象,并使用 pstring 来操作这个对象。那么在这个情况下,我们就必须设计一个析构函数。

析构函数是这样编写的:(可以在类的里面声明,定义写在类的外面,)

class NoName{
public:
    NoName():pstring(new std::string)
        , i(0), d(0){
        cout << "构造函数被调用了!" << endl;
    }
    ~NoName();
NoName::~NoName(){
    cout << "析构函数被调用了!" << endl;
}

析构函数是这样写的: ~NoName() ,它与构造函数唯一的区别就是,前面都加了一个 ~ 符号。 析构函数都是没有参数的,也就是说:析构函数永远只能写一个。
按照 C++ 的要求,只要有 new 就要有相应的 delete 。这个 new 是在构造函数里 new 的,就是出生的时候。所以在死掉的时候,就是调用析构函数时,我们必须对指针进行 delete 操作。

我们来在main() 函数中创建一个 NoName 实例对象来 测试一下:

int main(){
    NoName a;

    return 0;
}

并且在 main() 函数的 } 这一行添加一个断点,如图所示:

这里写图片描述

运行输出:

构造函数被调用了!
析构函数被调用了!

在定义 a 对象的时候,调用了 NoName 类的构造函数,在main() 函数执行完的时候,就是执行完 return 0; 这句话后,main() 函数的执行域结束,所以就要杀掉 a 对象,所以这个时候会调用 NoName 类的析构函数。

那么,如果我们在 main() 函数中使用 new 关键字来创建一个 NoName 类的实例化对象,会出现什么样的运行效果呢?
main() 函数中的代码如下:

int main(){
    NoName a;
    NoName *p = new NoName;

    return 0;
}

运行输出:

构造函数被调用了!
构造函数被调用了!
析构函数被调用了!

这里使用 new 创建的对象,就必须要使用 delete 来释放它。 牢牢的记住:new 和 delete 是一对。正确的代码是下面这个样子的:

int main(){
    NoName a;
    NoName *p = new NoName;

    delete p;
    return 0;
}

运行输出:

构造函数被调用了!
构造函数被调用了!
析构函数被调用了!
析构函数被调用了!

构造函数 和 析构函数 各有各的用途,在构造函数中,我们来获取资源;在析构函数中,我们来释放资源。释放了之后,这些资源就会被回收,可以被重新利用。
比如说,我们在构造函数里打开文件,在析构函数里关闭打开的文件。这是一个比较好的做法。
在构造函数里,我们去连接数据库的连接,在析构函数里关闭数据库的连接。
在构造函数里动态的分配内存,那么在析构函数里把动态分配的内存回收。

构造函数 和 析构函数 之间的操作是向对应的。
如果我们不写析构函数,C++ 会帮我们写一个析构函数。C++帮我们写的这个析构函数只能做一些很简单的工作,它不会帮助我们去打开文件、连接数据库、分配内存这些操作,相应的回收,它也不会给我们写。所以需要我们自己手动的写。(如果要做这些操作,我们必须自己写。)

如果我们自己写了析构函数,记住三个原则:
如果你写了析构函数,就必须同时写赋值构造函数 和 赋值操作符。你不可能只写一个。

赋值构造函数:

在赋值的时候,不是讲指针赋值过来,而是将指针对应指向的字符串赋值过来,这是最关键的一步。

因为我们写了析构函数,就必须要将赋值构造函数写上:

class NoName{
public:
    NoName():pstring(new std::string)
        , i(0), d(0){
        cout << "构造函数被调用了!" << endl;
    }
    NoName(const NoName & other);
    ~NoName();
NoName::NoName(const NoName & other){
    pstring = new std::string;
    *pstring = *(other.pstring);
    i = other.i;
    d = other.d;
}

除了要写 赋值构造函数,还要写赋值操作符。

class NoName{
public:
    NoName():pstring(new std::string)
        , i(0), d(0){
        cout << "构造函数被调用了!" << endl;
    }
    NoName(const NoName & other);
    ~NoName();

    NoName& operator =(const NoName &rhs);
NoName& NoName::operator=(const NoName &rhs){
    pstring = new std::string;
    *pstring = *(other.pstring);
    i = other.i;
    d = other.d;
    return *this;
}

只要你写了析构函数,就必须要写 赋值构造函数 和 赋值运算符,这就是著名的 三法则 (rule of three)



总结:

在设计一个类的时候,如果我们一个构造函数都没有写,那么 C++ 会帮我们写一个构造函数。只要我们写了一个构造函数,那么 C++ 就不会再帮我们写构造函数了。

构造函数可以重载,可以写很多个,析构函数不能重载,只能写一个。如果我们没有写析构函数,C++会自动帮我们写一个析构函数。那么在工作的时候,我们写的析构函数会被调用,调用完成之后,C++会执行它自动生成的析构函数。

如果我们写的类是一个没有那么复杂的类,我们可以不需要写析构函数。如果一个类只要有这些情况:打开文件、动态分配内存、连接数据库。简单的说:就是只要构造函数里面有了 new 这个关键词,我们就需要自己手动编写析构函数。

那么如果我们写了析构函数,就必须要注意三法则:同时编写:析构函数、赋值构造函数、赋值运算符。

完整的代码:

#include <iostream>
#include <string>

using namespace std;

class NoName{
public:
    NoName():pstring(new std::string)
        , i(0), d(0){
        cout << "构造函数被调用了!" << endl;
    }
    NoName(const NoName & other);
    ~NoName();

    NoName& operator =(const NoName &rhs);
private:
    std::string * pstring;
    int i;
    double d;
};

NoName::~NoName(){
    cout << "析构函数被调用了!" << endl;
}

NoName::NoName(const NoName & other){
    pstring = new std::string;
    *pstring = *(other.pstring);
    i = other.i;
    d = other.d;
}

NoName& NoName::operator=(const NoName &rhs){
    pstring = new std::string;
    *pstring = *(rhs.pstring);
    i = rhs.i;
    d = rhs.d;
    return *this;
}

int main(){
    NoName a;
    NoName *p = new NoName;

    delete p;
    return 0;
}
详解C++中的析构函数 析构函数和构造函数类似,对于内置类型不做处理,对于自定义类型会去调用它的析构函数,因此如果我们不写析构函数,但是对象存在动态开辟空间的行为,并且我们想释放这块开辟的空间,那么就会造成内存泄漏但是仔细想一下,如果我们的对象成员变量中存在指针,但如果他是一个文件指针或者一个迭代器,那么我们就希望调用析构函数不会将其置空,所以析构函数到底释放哪些资源应该由我们自己决定。 阅读详情

相关推荐

C++ 析构函数

C++ 构造函数

冲冲冲 3822

C++入门-----析构函数

析构函数

weixin_52669146的博客 7525

C++为什么父类析构函数要定义为虚析构函数

C++为什么父类析构函数要定义为虚析构函数

qq_53906512的博客 2308

【C++】析构函数

在开辟空间时,需要构造函数来开辟空间,对应,作用域退出时也需要一个函数做“收尾”的工作,与构造函数对应——析构函数析构函数和构造函数作用相反,用于释放对象的内存空间如果程序员未写构造函数,那么系统也会提供一个默认的构造函数,同样,如果程序员未写析构函数,那么系统也会提供一个默认的析构函数,在当前对象退出时,自动调用,进行释放空间。

qq_53830608的博客 4267

Prometheus+Grafana部署及企业微信邮件/群消息告警通知配置

本文详细介绍了在Ubuntu 22.04系统上部署普罗米修斯监控系统的完整流程。首先说明了系统配置要求(2核CPU、4G内存、100G硬盘),然后分步骤指导下载、解压和安装普罗米修斯服务。文章包含配置prometheus.yml文件、启动服务、设置系统服务等关键操作,并提供了访问9090端口验证服务的方法。接着介绍了通过node_exporter监控Linux主机的配置过程,包括安装、启动服务和修改普罗米修斯配置文件添加监控项。最后还涉及了mysqld_exporter的部署流程,用于监控MySQL数据库服

m0_58761900的博客 1640

OpenMV识别颜色源码

【代码】OpenMV识别颜色源码。

dxt258013的博客 403

C++中的虚析构函数

Cpp中的虚析构函数 1.虚析构函数的作用:为了避免内存泄漏,而且是当子类中会有指针成员变量时才会使用到。即虚析构函数使得在删除指向子类对象的基类指针时,可以调用子类的析构函数来实现释放子类中堆内存的目的,从而防止内存泄漏。 2.C++中开发中,基类中的析构函数一般都是虚函数,如下面的例子: #include <iostream> using namespace st...

CurryCoder的个人博客 1万+

第三章:ESP32零基础教学 - 3.4 蓝牙通信

本文详细介绍了如何在ESP32上实现经典蓝牙和BLE通信,并提供了代码解释和示例。通过这些示例,你可以轻松地将蓝牙功能集成到你的物联网项目中。无论是经典蓝牙的简单串口通信,还是BLE的灵活服务架构,ESP32都能满足你的需求。

Hi__gril的博客 4020

C++析构函数

类的6个默认成员函数:如果一个类中什么成员都没有,简称为空类。空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

qq_74013365的博客 2358

基于STM32电压检测和电流检测

1.可测量直流电压0~36V,适用于低电压电子电路中。 2.可测量直流电0~5A范围内,目前采用的ACS712测量量程为5A,该模块有多个量程,可测量到20A 3.实时功率监测 4.电池电量监测(采用电压压降方式计算)

weixin_44453694的博客 6万+

Android WIFI体系:深入解析WifiLock与MulticastLock的底层实现与性能优化

本文深入解析Android WIFI体系中WifiLock与MulticastLock的底层实现机制与性能优化策略。WifiLock通过阻止Wi-Fi休眠提升网络性能,尤其WIFI_MODE_FULL_HIGH_PERF模式可显著降低延迟;MulticastLock则控制组播数据接收,但会增加功耗。文章详细探讨了其与wpa_supplicant、HAL层的交互,并提供高性能场景下的优化实践与功耗平衡方案。

php55的博客 1079

cpp——类——析构函数

概述 析构函数特点: 函数名为“~类名”,用来标记和识别析构函数 没有返回值,析构函数是对自身的销毁行为,返回值无意义,因为没有返回值的接收者 形参列表为空,所以析构函数没有重载,唯一的 构造函数VS析构函数: 构造函数是对自身的初始化,生成(定义)对象时自动调用 析构函数是对自身的销毁,销毁对象时自动调用 辅助类 class CAnimal { public: CAnimal() : mGroup(0) { cout << "CAnimal()" << endl;

mardax的专栏 3000

简单VASP计算INCAR设置(结构优化OPT、静态自洽SCF、能带BAND、态密度DOS)

改变 K 点、NBANDS、晶胞、ENCUT、POTCAR、自旋或 SOC 后要检查兼容性。该参数不参与物理计算,因此不会改变总能量、受力、应力或最终结构。如果研究的是金属、磁性材料、表面、二维材料、分子、缺陷、DFT+U、杂化泛函或强自旋轨道耦合体系,部分参数必须调整。适合已经用 IBRION = 2 预优化、力较小、自由度较多的结构。在 IBRION = 1、2、3 中,它只是内部缩放因子。“不能修改”不是程序禁止修改,而是修改后会改变理论模型、数值精度或能量参考,使结果不能直接比较。

weixin_51420530的博客 125

C++中虚析构函数的作用

    我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明:        有下面的两个类:class ClxBase{public:    ClxBase() {};    virtual ~ClxBase() {};    virtual void DoSomething() { cout  "Do something 

寒星轩 19万+

【STK】手把手教你利用STK进行仿真-STK软件简介02 STK专业分析模块

STK/Astrogator是一个交互式轨道机动和深空探测计划工具,用于飞行器运行及任务分析,通过定义推力模型、目标星历、飞行器姿态,提供轨道机动的解决及优化方案。应用Astrogator分析轨道机动的可见性和地面站覆盖,用户可以快速、方便地进行全局分析。任务控制序列保存在STK场景中,用于任务运行、快速制定精确轨道机动方案。为在轨运行的飞行器制定或执行机动计划时,分析人员可以根据飞行过程数据,如发动机定标参数、实际初始轨道,计算出推进器点火和点火时机数据,用于发出指令及精炼机动计划。

weixin_44184852的博客 1864

微信小程序中使用画布canvas实现动态心电图绘制

近期,接了个项目,三端(小程序、PC、公众号)同步开发,PC端没的问题,以前一直做的就是PC端,但是小程序和公众号之前没有做过,只能通过这个项目,边做边学了。人家都说小程序用原生的特别难,大部分都用uniapp开发,说是这个方便快捷,还能写app呢,因为我们的项目,需要用到蓝牙采集数据、画布画仪表盘以及心电图等,所以我们不太敢用uniapp开发,硬着头皮开始用原生开发。开发的过程中,也遇到过很多问题,但是好在经过我们团队的不懈努力,问题基本都解决了。下面我就来分享一下,在小程序中,如何通过canvas。

穆雄雄的博客 3652

【C++ | 析构函数】类的析构函数详解

👉本文主要介绍类的析构函数的声明、定义、使用,以及析构函数在什么时候被调用。其实析构函数很简单,当你需要在对象被销毁时释放资源或内存时,就自己定义一个析构函数。

wkd_007的博客 4407

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

入门cpp之构造函数和析构函数

int _month;int _day;对于上面这个类,我们每次创建一个Date类型的变量,都需要调用Init函数去初始化,难免会有忘记初始的时候。cpp中有构造函数可以在变量创建时,自动将信息设置进去,这就是构造函数。构造函数是一个特殊的成员函数,名字与类名相同创建类类型对象时由编译器自动调用,以保证每个数据成员都有一个合适的初始值,并且在对象整个生命周期内只调用一次。

zyzyzy_mhmhmh的博客 832

IDEA的使用指南

IDEA基于java的使用手册,可以最快速的上手,在使用中不断的丰富自己的使用技巧.

Outlook Express 6 (OE6) for Win7/Win8/Win10

英文版 Outlook Express6.0, 兼容Win7/Win10/WinXP,解压就可用。

Cherno的Cpp教程笔记010:C++ 构造与析构函数

无构造函数(输出为随机值,即为其分配的地址的值)加上构造函数(初始化为0)

ResumeProject的博客 258

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

析构函数 cpp

3. 自动调用:当对象的生命周期结束时(例如,一个局部对象的作用域结束,或者使用 delete 删除 一个动态分配的对象),析构函数会被自动调用。析构函数特别重要,尤其是在涉及动态分配的资源(如内存、文件句柄、网络连接等)的情 况下。1. 名称:析构函数的名称由波浪号( ~ )后跟类名构成,如 ~MyClass()。2. 无返回值和参数:析构函数不接受任何参数,也不返回任何值。5. 继承和多态:如果一个类是多态基类,其析构函数应该是虚的。和构造函数一样,都是特殊的成员函数,析构函数是C++中的一。

qq_65305227的博客 650

C/Cpp / C++ 构造函数和析构函数可以是虚函数吗

答案 构造函数不可以是虚函数,而析构函数可以且常常是虚函数。 原因 1、构造函数不可以是虚函数 当类中声明虚函数时,编译器会在类中生成一个虚函数表,虚函数表是一个存储成员函数指针的数据结构。 虚函数表是由编译器自动生成与维护的,virtual成员函数会被编译器放入虚函数表中,当存在虚函数时,每个对象都有一个指向虚函数的指针(vptr指针)。在实现多态的过程中,父类和派生类都有vptr指针。 vptr的初始化:当对象在创建时,由编译器对 vptr 指针进行初始化。在定义子类对象时,vptr 先指向

布袋和尚 1260

c++析构函数

分析: 在main函数中创建了t0,t1,t2,t3几个对象,这里先说一下C++创建对象的三种不同方式: 1、Test p1(1); //栈中分配内存 2、Test p2 = Test(2);        //栈中分配内存,跟方法1相同,是方法1的完整模式 3、Test *p3 = new Test(3);     //堆中分配内存 方法1、2中都是在栈中分配内存,在栈中内存由系统自动的去分配和释放,而使用new创建的指针对象是在堆中分

scarificed的博客 5387

C++中基类的析构函数为什么要用virtual虚析构函数

C++中基类的析构函数为什么要用virtual虚析构函数, 弄清楚为什么。

IIcyZhao's Road 1万+

C++ 类 析构函数

C++ 类 析构函数 阅读目录 一、析构函数的定义 二、析构函数的调用 三、构造函数和析构函数的调用情况 四、私有析构函数 回到顶部 一、析构函数的定义 析构函数为成员函数的一种,名字与类名相同,在前面加‘~’没有参数和返回值在C++中“~”是位取反运算符。一个类最多只能有一个析构函数。析构函数不返回任何值,没有函数类型,也没有函数参数,因此它不能被重载。 构造函数可能...

cxu123321的博客 1562

【C++ 析构函数】C++ 私有析构函数的作用

C++ 私有析构函数的作用

探索C++编程的奥秘,分享深入的技术见解和实践,旨在激发读者创造力与解决问题的思维。 2088
上一篇: Auto Control 001 自动控制原理 自动控制的一般概念
下一篇: C++ 重载操作符- 01 简单的入门
AoboSir
博客等级 码龄10年 996粉丝 285原创
评论 10
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值