C++中的析构器(Destructor)(也称为析构函数)

news/2025/2/4 12:17:18/

在C++中,析构器(Destructor)也称为析构函数,它是一种特殊的成员函数,用于在对象销毁时进行资源清理工作。以下是关于C++析构器的详细介绍:

析构函数的特点

  1. 名称与类名相同,但前面有一个波浪号 ~:例如,如果类名为 MyClass,那么析构函数的名称就是 ~MyClass
  2. 没有返回类型:和构造函数一样,析构函数也不声明返回类型,甚至连 void 也不允许。
  3. 不接受任何参数:析构函数不能有参数,因此不能被重载。
  4. 自动调用:当对象的生命周期结束时,析构函数会被自动调用。

析构函数的作用

析构函数主要用于释放对象在其生命周期内所占用的资源,比如动态分配的内存、打开的文件、网络连接等。如果不进行资源清理,可能会导致内存泄漏或其他资源泄漏问题。

示例代码

1. 简单示例
#include <iostream>class MyClass {
public:MyClass() {std::cout << "Constructor called" << std::endl;}~MyClass() {std::cout << "Destructor called" << std::endl;}
};int main() {{MyClass obj; // 创建对象,调用构造函数} // 对象的作用域结束,调用析构函数return 0;
}

代码解释

  • MyClass 类中定义了构造函数和析构函数。当在 main 函数的内部代码块中创建 MyClass 对象 obj 时,构造函数会被自动调用。当代码块执行结束,对象 obj 的生命周期结束,析构函数会被自动调用。
2. 动态内存管理示例
#include <iostream>class ArrayWrapper {
private:int* arr;int size;
public:ArrayWrapper(int s) : size(s) {arr = new int[size]; // 动态分配内存std::cout << "Constructor: Allocated array of size " << size << std::endl;}~ArrayWrapper() {delete[] arr; // 释放动态分配的内存std::cout << "Destructor: Freed array of size " << size << std::endl;}
};int main() {{ArrayWrapper wrapper(5); // 创建对象,调用构造函数进行内存分配} // 对象的作用域结束,调用析构函数释放内存return 0;
}

代码解释

  • ArrayWrapper 类的构造函数使用 new 运算符动态分配了一个整数数组。析构函数使用 delete[] 运算符释放了这个数组所占用的内存。当 wrapper 对象的生命周期结束时,析构函数会被自动调用,从而避免了内存泄漏。

析构函数的调用时机

  1. 对象离开其作用域:当对象在一个代码块中定义,代码块执行结束时,对象的作用域结束,析构函数会被调用。
  2. 使用 delete 运算符删除动态分配的对象:如果使用 new 运算符动态创建对象,使用 delete 运算符删除对象时,析构函数会被调用。
#include <iostream>class MyClass {
public:~MyClass() {std::cout << "Destructor called" << std::endl;}
};int main() {MyClass* obj = new MyClass(); // 动态创建对象delete obj; // 删除对象,调用析构函数return 0;
}
  1. 对象是类的成员,类的对象被销毁:如果一个类包含另一个类的对象作为成员,当包含类的对象被销毁时,成员对象的析构函数也会被调用。
#include <iostream>class InnerClass {
public:~InnerClass() {std::cout << "InnerClass destructor called" << std::endl;}
};class OuterClass {
private:InnerClass inner;
public:~OuterClass() {std::cout << "OuterClass destructor called" << std::endl;}
};int main() {OuterClass outer; // 创建包含类的对象// 当 main 函数结束,outer 对象被销毁,先调用 InnerClass 的析构函数,再调用 OuterClass 的析构函数return 0;
}

注意事项

  • 如果类中没有显式定义析构函数,编译器会自动提供一个默认析构函数。默认析构函数不执行任何操作。
  • 如果类中涉及动态内存分配或其他资源管理,一定要显式定义析构函数,以确保资源被正确释放。
  • 析构函数通常应该是虚函数,特别是在基类中,这样可以确保在通过基类指针删除派生类对象时,派生类的析构函数也能被正确调用,避免资源泄漏。
#include <iostream>class Base {
public:virtual ~Base() {std::cout << "Base destructor called" << std::endl;}
};class Derived : public Base {
public:~Derived() {std::cout << "Derived destructor called" << std::endl;}
};int main() {Base* ptr = new Derived();delete ptr; // 由于基类析构函数是虚函数,会先调用 Derived 的析构函数,再调用 Base 的析构函数return 0;
}

http://www.ppmy.cn/news/1569225.html

相关文章

csapp笔记3.6节——控制(1)

本节解决了x86-64如何实现条件语句、循环语句和分支语句的问题 条件码 除了整数寄存器外&#xff0c;cpu还维护着一组单个位的条件码寄存器&#xff0c;用来描述最近的算数和逻辑运算的某些属性。可检测这些寄存器来执行条件分支指令。 CF&#xff08;Carry Flag&#xff09…

蓝桥杯真题——小秘密(省模拟赛)

目录 题目链接&#xff1a;6.小秘密 - 蓝桥云课 题目描述 输入描述 输出描述 输入输出样例 样例说明 思路 那具体的步骤应该是这样的&#xff1a; 那具体的代码实现应该如何处理呢&#xff1f; 解法一&#xff1a;求解环的个数 Java写法&#xff1a; C写法&#xf…

搜索与图论复习1

1深度优先遍历DFS 2宽度优先遍历BFS 3树与图的存储 4树与图的深度优先遍历 5树与图的宽度优先遍历 6拓扑排序 1DFS&#xff1a; #include<bits/stdc.h> using namespace std; const int N10; int n; int path[N]; bool st[N]; void dfs(int u){if(nu){for(int i0;…

图论——最小生成树的扩展应用

最小生成树相关原理 acwing1146.新的开始 假设存在一个“超级发电站” 在每一个矿井修发电站相当于从这个“超级发电站”到各个矿井连一条长度为 v [ i ] v[i] v[i]的边。 这样一来这就是一个最短路的模板题。 #include <iostream> #include <cstring> using na…

简易CPU设计入门:指令单元(二)

项目代码下载 请大家首先准备好本项目所用的源代码。如果已经下载了&#xff0c;那就不用重复下载了。如果还没有下载&#xff0c;那么&#xff0c;请大家点击下方链接&#xff0c;来了解下载本项目的CPU源代码的方法。 CSDN文章&#xff1a;下载本项目代码 上述链接为本项目…

理解红黑树

简介&#xff1a;红黑树是一种自平衡二叉查找树&#xff0c;由鲁道夫贝尔&#xff08;Rudolf Bayer&#xff09;在1972年发明&#xff0c;最初称为“对称二叉B树”。它的设计旨在解决普通二叉查找树在频繁插入和删除操作时可能退化为链表的问题&#xff0c;从而保持高效的查找、…

ubuntu18.04环境下,Zotero 中pdf translate划线后不翻译问题解决

问题&#xff1a; 如果使用fastgithub&#xff0c;在/etc/profile中设置全局代理&#xff0c;系统重启后会产生划线后不翻译的问题&#xff0c;包括所有翻译代理均不行。终端中取消fastgithub代理&#xff0c;也不行。 解决&#xff1a; 1&#xff09;不在/etc/profile中设置…

Safari常用快捷键

一、书签边栏 1、显示或隐藏书签边栏&#xff1a;Control-Command-1 2、选择下一个书签或文件夹&#xff1a;向上头键或向下头键 3、打开所选书签&#xff1a;空格键 4、打开所选文件夹&#xff1a;空格键或右箭头键 5、关闭所选文件夹&#xff1a;空格键或左箭头键 6、更…