目录一、什么是析构函数二、析构函数写法三、析构函数的特点四、析构函数什么时候调用五、析构函数不是销毁对象本身六、为什么需要析构函数七、用析构函数释放动态内存八、析构函数的调用顺序九、析构函数和构造函数的区别十、什么时候必须写析构函数十一、小结一、什么是析构函数析构函数是C类中的一种特殊成员函数。它会在队形生命周期结束时自动调用主要作用是清理对象在使用过程中申请的资源。比如一个类中如果动态申请了内存那么在对象销毁前就应该把这块内存释放掉避免内存泄露。析构函数和构造函数刚好对应构造函数对象创建时自动调用用来初始化对象 析构函数对象销毁时自动调用用来清理资源二、析构函数写法析构函数的函数名是在类名前面加 ~。基本格式~类名() { // 清理资源 }例如class Date { public: ~Date() { cout Date destructor endl; } };这里~Date()就是 Date 的析构函数。三、析构函数的特点析构函数有几个重要的特点1. 函数名是在类名前加 ~ 2. 没有返回值 3. 没有参数 4. 不能重载 5. 对象销毁时自动调用。因为析构函数没有参数所以一个类中只能有一个析构函数不能像构造函数那样重载。四、析构函数什么时候调用当对象生命周期结束时析构函数会自动调用。例如局部对象离开作用域时#include iostream using namespace std; class Date { public: Date() { cout Date constructor endl; } ~Date() { cout Date destructor endl; } }; int main() { Date d; return 0; }运行结果Date constructor Date destructor当执行Date d;时构造函数自动调用。当 main 函数结束对象 d 生命周期结束时析构函数自动调用。五、析构函数不是销毁对象本身这一点很重要。析构函数并不是负责把对象本是谁呢销毁。对象空间的创建和释放由编译器管理析构函数主要负责清理对象内部申请的资源。比如class Stack { private: int* _array; };如果 _array 指向的是动态申请的空间那么对象销毁前就应该释放这块空间。所以析构函数更准确的作用是清理对象持有的资源而不是销毁对象本身。六、为什么需要析构函数假设我们写一个栈类在初始化时动态申请空间class Stack { public: void Init(int capacity) { _array (int*)malloc(sizeof(int) * capacity); _top 0; _capacity capacity; } private: int* _array; int _top; int _capacity; };如果对象用完后不是放 _array 指向的空间就会造成内存泄漏。在C语言中我们通常要手动写 Destory 函数void Destory() { free(_array); _array nullptr; _top 0; _capacity 0; }但是这样有一个问题如果忘记手动调用 Destory就可能导致内存泄漏。C中可以把资源清理工作放到析构函数里让对象销毁时自动完成清理。七、用析构函数释放动态内存示例#include iostream using namespace std; class Stack { public: Stack(int capacity 4) { _array (int*)malloc(sizeof(int) * capacity); _top 0; _capacity capacity; } ~Stack() { if (_array ! nullptr) { free(_array); _array nullptr; } _top 0; _capacity 0; cout Stack destructor endl; } private: int* _array; int _top; int _capacity; }; int main() { Stack s; return 0; }当 s 生命周期结束时析构函数会自动调用释放 _array 指向的动态空间。这样就不用手动调用 Destory 了。八、析构函数的调用顺序如果在同一个作用域中创建多个对象析构函数通常和构造函数相反。例如#include iostream using namespace std; class Date { public: Date(int id) { _id id; cout Date _id constructor endl; } ~Date() { cout Date _id destructor endl; } private: int _id; }; int main() { Date d1(1); Date d2(2); return 0; }运行结果Date 1 constructor Date 2 constructor Date 2 destructor Date 1 destructor可以看到先构造 d1再构造 d2 先析构 d2再析构 d1。这符合栈的特点后创建的对象先销毁。九、析构函数和构造函数的区别对比项构造函数析构函数调用时机对象创建时对象销毁时主要作用初始化对象清理资源函数名与类名相同类名前加~返回值没有返回值没有返回值参数可以有参数不能有参数是否能重载可以重载不能重载调用方式自动调用自动调用构造函数和析构函数共同管理对象的生命周期。十、什么时候必须写析构函数如果类中没有申请资源一般可以不写析构函数让编译器自动生成即可。例如class Date { private: int _year; int _month; int _day; };这种类只有普通成员变量不涉及动态资源通常不需要自己写析构函数。但是类中有动态申请的内存 打开的文件 网络连接 系统资源就应该考虑写析构函数进行释放。比如int* _array;如果它指向 malloc 或 new 申请的空间就需要在析构函数中释放。十一、小结本篇主要学习了C中的析构函数。需要记住析构函数是在类名前加 ~析构函数没有返回值析构函数没有参数析构函数不能重载析构函数再对象销毁时自动调用析构函数主要用于清理对象持有的资源析构函数不销毁对象本身如果类中动态申请了内存通常需要在析构函数中释放多个局部对象的析构顺序通常和构造顺序相反。析构函数是C类和对象中的重要内容和构造函数一起构成了对象的生命周期管理的基础。后面学习拷贝构造、赋值运算符重载、动态内存管理时还会继续用到它。
C++学习笔记17:析构函数
目录一、什么是析构函数二、析构函数写法三、析构函数的特点四、析构函数什么时候调用五、析构函数不是销毁对象本身六、为什么需要析构函数七、用析构函数释放动态内存八、析构函数的调用顺序九、析构函数和构造函数的区别十、什么时候必须写析构函数十一、小结一、什么是析构函数析构函数是C类中的一种特殊成员函数。它会在队形生命周期结束时自动调用主要作用是清理对象在使用过程中申请的资源。比如一个类中如果动态申请了内存那么在对象销毁前就应该把这块内存释放掉避免内存泄露。析构函数和构造函数刚好对应构造函数对象创建时自动调用用来初始化对象 析构函数对象销毁时自动调用用来清理资源二、析构函数写法析构函数的函数名是在类名前面加 ~。基本格式~类名() { // 清理资源 }例如class Date { public: ~Date() { cout Date destructor endl; } };这里~Date()就是 Date 的析构函数。三、析构函数的特点析构函数有几个重要的特点1. 函数名是在类名前加 ~ 2. 没有返回值 3. 没有参数 4. 不能重载 5. 对象销毁时自动调用。因为析构函数没有参数所以一个类中只能有一个析构函数不能像构造函数那样重载。四、析构函数什么时候调用当对象生命周期结束时析构函数会自动调用。例如局部对象离开作用域时#include iostream using namespace std; class Date { public: Date() { cout Date constructor endl; } ~Date() { cout Date destructor endl; } }; int main() { Date d; return 0; }运行结果Date constructor Date destructor当执行Date d;时构造函数自动调用。当 main 函数结束对象 d 生命周期结束时析构函数自动调用。五、析构函数不是销毁对象本身这一点很重要。析构函数并不是负责把对象本是谁呢销毁。对象空间的创建和释放由编译器管理析构函数主要负责清理对象内部申请的资源。比如class Stack { private: int* _array; };如果 _array 指向的是动态申请的空间那么对象销毁前就应该释放这块空间。所以析构函数更准确的作用是清理对象持有的资源而不是销毁对象本身。六、为什么需要析构函数假设我们写一个栈类在初始化时动态申请空间class Stack { public: void Init(int capacity) { _array (int*)malloc(sizeof(int) * capacity); _top 0; _capacity capacity; } private: int* _array; int _top; int _capacity; };如果对象用完后不是放 _array 指向的空间就会造成内存泄漏。在C语言中我们通常要手动写 Destory 函数void Destory() { free(_array); _array nullptr; _top 0; _capacity 0; }但是这样有一个问题如果忘记手动调用 Destory就可能导致内存泄漏。C中可以把资源清理工作放到析构函数里让对象销毁时自动完成清理。七、用析构函数释放动态内存示例#include iostream using namespace std; class Stack { public: Stack(int capacity 4) { _array (int*)malloc(sizeof(int) * capacity); _top 0; _capacity capacity; } ~Stack() { if (_array ! nullptr) { free(_array); _array nullptr; } _top 0; _capacity 0; cout Stack destructor endl; } private: int* _array; int _top; int _capacity; }; int main() { Stack s; return 0; }当 s 生命周期结束时析构函数会自动调用释放 _array 指向的动态空间。这样就不用手动调用 Destory 了。八、析构函数的调用顺序如果在同一个作用域中创建多个对象析构函数通常和构造函数相反。例如#include iostream using namespace std; class Date { public: Date(int id) { _id id; cout Date _id constructor endl; } ~Date() { cout Date _id destructor endl; } private: int _id; }; int main() { Date d1(1); Date d2(2); return 0; }运行结果Date 1 constructor Date 2 constructor Date 2 destructor Date 1 destructor可以看到先构造 d1再构造 d2 先析构 d2再析构 d1。这符合栈的特点后创建的对象先销毁。九、析构函数和构造函数的区别对比项构造函数析构函数调用时机对象创建时对象销毁时主要作用初始化对象清理资源函数名与类名相同类名前加~返回值没有返回值没有返回值参数可以有参数不能有参数是否能重载可以重载不能重载调用方式自动调用自动调用构造函数和析构函数共同管理对象的生命周期。十、什么时候必须写析构函数如果类中没有申请资源一般可以不写析构函数让编译器自动生成即可。例如class Date { private: int _year; int _month; int _day; };这种类只有普通成员变量不涉及动态资源通常不需要自己写析构函数。但是类中有动态申请的内存 打开的文件 网络连接 系统资源就应该考虑写析构函数进行释放。比如int* _array;如果它指向 malloc 或 new 申请的空间就需要在析构函数中释放。十一、小结本篇主要学习了C中的析构函数。需要记住析构函数是在类名前加 ~析构函数没有返回值析构函数没有参数析构函数不能重载析构函数再对象销毁时自动调用析构函数主要用于清理对象持有的资源析构函数不销毁对象本身如果类中动态申请了内存通常需要在析构函数中释放多个局部对象的析构顺序通常和构造顺序相反。析构函数是C类和对象中的重要内容和构造函数一起构成了对象的生命周期管理的基础。后面学习拷贝构造、赋值运算符重载、动态内存管理时还会继续用到它。