C++中何时及如何使用析构函数

news/2024/7/2 13:52:59

C++中何时及如何使用析构函数

析构函数不返回任何值,没有返回类型,也没有函数参数。由于没 有函数参数,因此它不能被重载。换言之,一个类可以有多个构造函数,但是只能有一个析构函数。

何时调用析构函数:
(1)对象在程序运行超出其作用域时自动撤销,撤销时自动调用 该对象的析构函数。如函数中的非静态局部对象。
(2)如果用new运算动态地建立了一个对象,那么用delete运算释放该对象时,调用该对象的析构函数
与复制构造函数不同,编译器总是会为类生成一个析构函数,称为合成析构函数(synthesized destructor)。

合成析构函数按对象创建时的逆序撤销每个非静态成员,即它是按成员在类中声明次序的逆序撤销成员的。对于类类型的每个成员, 合成析构函数调用该成员的析构函数来撤销对象。

需要注意,合成析构函数并不删除指针成员所指向的对象,它需要程序员显式编写析构函数去处理。

每当对象不再在作用域内或通过 delete 被删除进而被销毁时,都将调用析构函数。这使得析构函数成为重置变量以及释放动态分配的内存和其他资源的理想场所。
使用 char*缓冲区时,您必须自己管理内存分配和释放,因此建议不要使用它们,而使用 std::string。 std::string 等工具都是类,它们充分利用了构造函数和析构函数,还有运算符,让您无需考虑分配和释放等内存管理工作。以下示例程序所示的类 MyString 在构造函数中为一个字符串分配内存,并在析构函数中释放它:

#include <iostream>
#include <string.h>
using namespace std;

class MyString
{
private:
    char* buffer;

public:
    MyString(const char* initString)  // constructor
    {
        if(initString != NULL)
        {
            buffer = new char [strlen(initString) + 1];
            strcpy(buffer, initString);
        }
        else 
            buffer = NULL;
    }

    ~MyString()
    {
        cout << "Invoking destructor, clearing up" << endl;
        if (buffer != NULL)
            delete [] buffer;
    }

    int GetLength() 
    {
        return strlen(buffer);
    }

    const char* GetString()
    {
        return buffer;
    }
};

int main()
{
    MyString sayHello("Hello from String Class");
    cout << "String buffer in sayHello is " << sayHello.GetLength();
    cout << " characters long" << endl;

    cout << "Buffer contains: " << sayHello.GetString() << endl;
}

输出:

String buffer in sayHello is 23 characters long
Buffer contains: Hello from String Class
Invoking destructor, clearing up

分析:

这个类封装了一个 C 风格字符串( MyString::buffer),让您使用字符串时无需分配和释放内存。我们最感兴趣的是第 9~18 行的构造函数 MyString( )以及第 20~25 行的析构函数~MyString( )。这个构造函数构造 MyString 对象。它通过输入参数获取一个输入字符串;然后使用标准库函数 strlen 确定输入字符串的长度,并使用 new 为字符缓冲区 buffer 分配内存(第 13 行);再使用标准库函数 strcpy 将输入字符串 initString 复制到 buffer 指向的新分配的内存中(第 14 行)。如果传递给参数 initString 的值为 NULL, MyString::buffer 也被初始化为 NULL(以防该指针包含随机值,否则使用它来访问内存单元将非常危险)。析构函数的代码确保构造函数分配的内存自动被归还给系统。它检查 MyString::buffer 是否为 NULL,如果不是,则对其执行 delete[],这对应于构造函数中的 new。注意到在 main() 中,程序员无需调用 new 和 delete。 MyString 类不仅对程序员隐藏了内存管理实现,还正确地释放了分配的内存。 main( )执行完毕时,将自动调用析构函数 ~MyString(),输出证明了这一点—其中包含析构函数中 cout 语句的输出。
类更好地处理了字符串,这是析构函数的众多用途之一。在更智能地使用指针方面,析构函数也扮演了重要角色。

注意:

析构函数不能重载,每个类都只能有一个析构函数。如果您忘记了实现析构函数,编译器将创建一个伪( dummy)析构函数并调用它。伪析构函数为空,即不释放动态分配的内存。

该文章会更新,欢迎大家批评指正。

推荐一个零声学院的C++服务器开发课程,个人觉得老师讲得不错,
分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容
点击立即学习:C/C++后台高级服务器课程


http://lihuaxi.xjx100.cn/news/1753020.html

相关文章

isdigit与atoi

记得看拒绝转载

STM32笔记-AD模数转换

目录 一、ADC介绍 二、ADC主要特征 三、ADC框图 1. ​​​​ 外部触发转换 ​ 2. 转换模式 3. 输入通道 4. 逻辑框图 四、校准 五、数据对齐 六、AD转换步骤 七、AD_Init(单通道AD转换)初始化函数配置 一、ADC介绍 1. 12位ADC是一种逐次逼近型模拟数字转换器。它有多达…

检查AirPods的电量至少有六种方法,难易明细的都有

本文提供了六种方法,包括使用iPhone或iPad、询问Siri以及检查AirPods手机壳本身的多种选项。 如何使用保护壳检查AirPods的电池 一个简单的方法是查看AirPods保护壳上的指示灯,以获取电池电量信息;这个选项没有其他选项那么详细。 把耳塞放进盒子里,然后检查一下灯的颜色…

基于蜜獾算法的无人机航迹规划-附代码

基于蜜獾算法的无人机航迹规划 文章目录 基于蜜獾算法的无人机航迹规划1.蜜獾搜索算法2.无人机飞行环境建模3.无人机航迹规划建模4.实验结果4.1地图创建4.2 航迹规划 5.参考文献6.Matlab代码 摘要&#xff1a;本文主要介绍利用蜜獾算法来优化无人机航迹规划。 1.蜜獾搜索算法 …

产品经理入门学习(三):产品解决方案

参考引用 黑马-产品经理入门基础课程 1. 需求分析 1.1 需求分析的目的 1.2 需求分析的方法 案例分析 福特公司的创始人亨利福特说&#xff1a;如果我当年去问顾客他们想要什么&#xff0c;他们肯定会告诉我&#xff1a;一匹更快的马 1.3 需求分析的实际应用 人性七宗罪&#…

Autosar诊断实战系列26-Dem(DTCEvent)要点及配置开发详解

本文框架 前言1. Dem及其与其他模块交互介绍1.1 与DCM模块交互1.1.1 0x14服务调用时序1.1.2 0x85服务调用时序1.1.3 0x19服务调用时序1.2 与Fim模块交互1.3 与NvM模块交互1.4 与BswM模块交互1.5 与其他BSW及APP模块交互2. Dem配置开发介绍2.1 DemGeneral配置2.1.1 DemGeneral一…

JavaScript基础入门02

目录 1.变量的使用 1.1基本用法 1.2理解 动态类型 2.基本数据类型 2.1number 数字类型 2.2数字进制表示 2.3特殊的数字值 2.4string 字符串类型 2.4.1基本规则 2.4.2转义字符 2.4.3求长度 2.4.4字符串拼接 2.5boolean 布尔类型 2.6undefined 未定义数据类型 2.7n…

动态路由协议OSPF优化提速特性

1.OSPF协议通信过程与部署&#xff1b; 2.OSPF协议在项目上的应用场景&#xff1b; 3.OSPF有哪些优化特性&#xff1f; - OSPF - 开放式最短路径优先 - 一个动态路由协议 - 路由协议 - 理解魏 运行在路由器的一个软件 - 目的&#xff1a;为了帮助路由器和路由器彼…