C++析构函数解析(destructors)

这篇具有很好参考价值的文章主要介绍了C++析构函数解析(destructors)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

析构函数destructors

名字与类名相同,在前面加‘~’, 没有参数和返回值,一个类最多只能有一个析构函数。

析构函数对象消亡时即自动被调用。可以定义析构函数来在对象消亡前做善后工作,比如释放分配的空间等。

如果定义类时没写析构函数,则编译器生成缺省析构函数。缺省析构函数什么也不做。

如果定义了析构函数,则编译器不生成缺省析构函数。

析构函数是与构造函数相对应的一种特殊函数,主要用于在对象生命周期结束时清理对象占用的内存资源。

在C++中,每个类都可以定义自己的析构函数,它由一个波浪号~和类名组成,并且不需要参数或返回值。通常情况下,需要清理动态分配的内存、关闭打开的文件、释放网络连接等等操作都可以在析构函数中实现。

在下面的示例代码中,我们定义了一个名为Person的类,其中包含有两个成员变量nameage,我们在这个类中定义了一个简单的析构函数,用于在对象被销毁时输出一条消息:

#include<iostream>
using namespace std;

class Person {
public:
    string name;
    int age;
    Person(string n, int a): name(n), age(a) { // 构造函数
        cout << "Object created." << endl;
    }
    ~Person(){                                 // 析构函数
        cout << "Object destroyed." << endl;
    }
};

int main() {
    Person p1("张三", 20);
    return 0;
}

在上述代码中,我们定义了一个Person对象p1,并初始化了它的属性(姓名和年龄)。在main()函数结束后,程序运行完毕,也就是Person对象p1的生命周期结束时,会自动调用析构函数~Person()来释放占用的内存资源。在这个析构函数中,我们简单地输出了一条消息“Object destroyed.”。

总之,析构函数是类的一个特殊函数,在对象生命周期结束时自动调用(或者手动调用),它的主要作用就是清理对象所占用的资源,例如动态分配的内存、打开的文件等。借助析构函数,我们能够更好地控制程序使用内存资源的方式,并避免出现内存泄漏等问题。

为什么需要析构函数

在C++中,我们经常要使用动态内存分配来创建对象,例如使用new关键字来为一个对象分配内存空间。由于程序运行完毕后需要释放这部分动态分配的内存空间,因此我们需要使用delete关键字来释放这些内存空间。

如果我们没有合理地释放这些内存,在程序执行一段时间之后,就会耗尽机器物理内存,导致系统崩溃或程序运行效率下降。因此,为了避免出现内存泄漏等问题,我们可以使用析构函数来释放所占用的内存资源。

此外,析构函数的另一个重要作用是帮助我们管理类中的各种数据结构和状态。通常我们可以使用析构函数来释放资源但需要注意的是,在大多数情况下,析构函数在对象被销毁时自动调用,程序员无需手动调用。

综上所述,析构函数是为了解决程序中动态内存申请和管理的问题而存在的,它是一种特殊的函数,当对象生命周期结束时自动调用,主要用于清理对象所占用的资源、还原对象的状态等。使用析构函数能够有效地管理内存资源,防止内存泄漏以及其它相关问题的发生。

析构函数和数组

在C++中,数组的生命周期也和其他对象一样;当程序执行到数组的作用域结束时,或者使用delete运算符来释放动态分配的数组空间时,数组也要被销毁。因此,如果一个类定义了析构函数,则它可以管理动态数组,并在销毁对象时自动调用。

下面是一个简单的示例代码,展示了如何在类中使用析构函数来管理动态数组:

#include<iostream>
using namespace std;

class Array{
private:
    int *arr;
    int size;
public:
    Array(int s):size(s) {          // 构造函数,创建一个大小为s的数组
        arr = new int[s];
    }
    ~Array() {                      // 析构函数,释放数组所占用的内存
        delete[] arr;
    }
};

int main(){
    Array a1(10);                  // 创建大小为10的数组对象
    return 0;
}

在上述代码中,我们定义了一个名为Array的类,其中包含一个指向int类型的指针arr,用于动态分配内存,并且定义了一个整型变量用于记录数组的大小。在类的构造函数Array(int s)中,我们使用new运算符为这个数组分配了s个元素的内存,并保存指向其地址的指针。然后,在析构函数~Array()中,我们使用delete[]运算符来释放数组的内存空间。

main()函数中,我们创建一个大小为10的数组对象a1,用于展示如何在类中使用析构函数来管理动态数组。当程序执行结束时,自动调用Array类的析构函数,进而自动释放动态分配的内存空间。

值得注意的是,在使用析构函数管理动态数组时需要小心一些细节问题,下面列出几点需要特别注意的事项:

  1. 析构函数应该使用delete[]运算符释放数组所占用的内存空间,否则可能会导致内存泄漏或程序崩溃。

  2. 如果在类中定义了其他指针类型的成员变量,例如char*型指针,则需要编写相应的析构函数来释放这些指针所指向的内存空间。

  3. 在使用动态数组时,应该进行异常处理,防止因为内存分配失败导致内存泄漏或程序崩溃。

  4. 除非有必要,否则不应该将动态数组作为类成员来使用,否则可能会破坏类的封装性和可移植性。如果必须使用动态数组作为类成员变量,则应该使用复制构造函数和赋值运算符来处理对象之间的拷贝和赋值操作。

总之,使用析构函数可以有效地管理动态数组并防止内存泄漏等问题,但需要程序员对其进行正确的使用与实现。

析构函数和运算符 delete

delete 运算导致析构函数调用。

Ctest * pTest;
pTest = new Ctest; //构造函数调用
、
pTest = new Ctest[3]; //构造函数调用3次
delete [] pTest; //析构函数调用3次

若new一个对象数组,那么用delete释放时应该写 []。否则只delete一个对象(调用一次析构函数)

析构函数在对象作为函数返回值返回后被调用

class CMyclass {
public:
~CMyclass() { cout << "destructor" << endl; }
};
CMyclass obj;
CMyclass fun(CMyclass sobj ) { //参数对象消亡也会导致析
//构函数被调用
return sobj; //函数调用返回时生成临时对象返回
}
int main(){
obj = fun(obj); //函数调用的返回值(临时对象)被
return 0; //用过后,该临时对象析构函数被调用
}

输出:
destructor
destructor
destructor

构造函数和析构函数什么时候被调用

构造函数和析构函数的调用时机如下:

构造函数:

  • 在创建对象时自动被调用,即当我们定义一个类的对象,使用它的构造函数来初始化该对象时就会被自动调用。
  • 构造函数还可以在派生类中显示调用基类的构造函数。这通常是通过在子类的成员初始化列表中调用它来实现的。

析构函数:

  • 当一个对象生命到达其范围的尽头或者当对动态分配内存空间的对象应用delete运算符时,析构函数将被自动调用。
  • 在一些情况下,析构函数也可以显式地调用来释放对象的资源。

例如,考虑下面这个小例子:

#include<iostream>
using namespace std;

class Person {
public:
    string name;
    int age;
    Person() {
        cout << "Constructor called!" << endl;
    }
    ~Person() {
        cout << "Destructor called!" << endl;
    }
};
int main() {
    Person p1;               // 创建Person类型的对象p1,此时构造函数被调用
    return 0;
}   

在上述代码中,我们定义了一个名为Person的类,并在其中定义了构造函数和析构函数。在main()函数中,我们创建一个Person类型的对象p1,它的定义触发了构造函数的调用;在程序结束之前,Person对象p1的范围已经结束,同时达到了它的生命周期结束这一条件,触发了析构函数的调用。

总之,构造函数和析构函数都将在对象创建和销毁时分别被自动调用。对于不同类型的类,当创建或销毁实例时,C++编译器会自动调用相应的构造函数和析构函数来处理相关的操作。

需要注意的是,如果一个类包含静态成员变量,则必须显式地定义该静态成员变量的构造函数和析构函数。因为静态对象必须在程序开始执行之前被初始化,在程序结束时被销毁。例如:

#include<iostream>
using namespace std;

class MyClass {
public:
    MyClass() {
        cout << "Constructor called." << endl;
    }
    ~MyClass() {
        cout << "Destructor called." << endl;
    }
};

class WithStaticMember{
public:
    static MyClass sm;    // 静态成员变量,必须显式定义其构造函数和析构函数
    WithStaticMember() {
        cout << "WithStaticMember constructor called." << endl;
    }
    ~WithStaticMember() {
        cout << "WithStaticMember destructor called." << endl;
    }
};

MyClass WithStaticMember::sm;  // 显式定义静态成员变量的构造函数和析构函数

int main() {
    WithStaticMember wsm;      // 创建对象wsm,此时调用相关构造函数
    return 0;
}

在上述代码中,我们定义了一个名为WithStaticMember的类,并在其中定义了包含一个静态成员变量sm的类成员。由于静态成员变量必须在类外部进行初始化,所以我们需要在程序文件级别上定义其构造函数和析构函数。在main()函数中,我们创建WithStaticMember类的实例wsm,此时相关构造函数自动调用;当程序结束时,对应的析构函数被自动调用。

总之,在包含静态成员变量的类中,必须显式定义其构造函数和析构函数以正确地初始化和销毁这些变量,否则会导致程序无法编译或运行异常。文章来源地址https://www.toymoban.com/news/detail-481524.html

到了这里,关于C++析构函数解析(destructors)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

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

    有了构造函数用来初始化成员,那么也应该有一个函数用来清理程序运行结束时的空间。就像实现栈时的Init和Destroy一样,所以就有了析构函数。 析构函数也是特殊的成员函数。与构造函数功能相反, 析构函数不是完成对对象本身的销毁 ,局部对象销毁工作是由编译器完成

    2024年02月16日
    浏览(32)
  • 022 - C++ 析构函数

    上期我们讨论了构造函数。认识了它是什么以及如何使用它。如果你没有看上一期,那么你一定要回去看一下。 今天我们要讨论一下它的“孪生兄弟”, 析构函数 ,它们在某些方面非常相似。 构造函数是你创建一个新的实例对象时运行,而析构函数是在销毁对象时运行。所

    2023年04月25日
    浏览(29)
  • C++析构函数详解

    创建对象时系统会自动调用构造函数进行初始化工作,同样,销毁对象时系统也会自动调用一个函数来进行清理工作,例如释放分配的内存、关闭打开的文件等,这个函数就是析构函数。 析构函数(Destructor)也是一种特殊的成员函数,没有返回值,不需要程序员显式调用(

    2023年04月08日
    浏览(26)
  • C++篇----构造函数和析构函数

    在很多时候,当写了初始化,动态开辟的,需要写销毁函数,写了销毁函数之后,但是却忘记了调用这些函数,忘记调用初始化函数还好,编译器会报错,但是如果是忘记调用销毁函数,那么编译器是不会报错,但是不能说这个程序就没错哦了,反而有很大的问题,存在内存

    2024年02月01日
    浏览(41)
  • 【C++初阶】构造函数和析构函数

    📖 默认成员函数 用户没有显式实现,编译器会自动生成的成员函数,称为默认成员函数。 构造函数 :完成对象的初始化工作。 析构函数 :完成对象空间的清理工作。 拷贝构造 :使用同类对象初始化创建对象。 赋值重载 :把一个对象赋值给另外一个对象(该对象已存在

    2024年02月17日
    浏览(46)
  • C++ 构造函数和析构函数 详解

    C++中用构造函数和析构函数来初始化和清理对象,这两个函数将会被编译器自动调用。对象的初始化和清理是非常重要的,如果我们不提供构造函数与析构函数,编译器会自动提供两个函数的空实现。 构造函数:主要作用于创建函数时对对象成员的属性赋值。 析构函数:主

    2024年02月02日
    浏览(47)
  • 『C++成长记』构造函数和析构函数

    🔥 博客主页: 小王又困了 📚 系列专栏: C++ 🌟 人之为学,不日近则日退  ❤️ 感谢大家点赞👍收藏⭐评论✍️ 目录 一、类的六个个默认成员函数 📒1.1认识默认成员函数  二、构造函数 📒2.1为什么要有构造函数 📒2.2构造函数的概念 📒2.3构造函数的特性 📒2.4编译器

    2024年02月05日
    浏览(43)
  • 【C++入门到精通】C++入门 —— 类和对象(构造函数、析构函数)

    目录 一、类的6个默认成员函数  二、构造函数 ⭕构造函数概念 ⭕构造函数的特点 ⭕常见构造函数的几种类型 三、析构函数      ⭕析构函数概念     ⭕析构函数的特点 ⭕常见析构函数的几种类型 四、温馨提示          这一篇文章是上一篇的续集(这里有上篇链接)

    2024年02月15日
    浏览(50)
  • 【零基础学习C++】构造函数与析构函数

    个人主页:【😊个人主页】 系列专栏:【❤️系列专栏】 期末复习笔记,感兴趣的可以收藏 C++用以初始化对象的数据成员的函数 构造函数要注意的知识点: 构造函数是没有返回值类型的。 构造函数的函数名必须 与类名一致。 构造函数并不是由我们手动调用的, 构造函数

    2024年02月11日
    浏览(42)
  • 【C++杂货铺】构造函数和析构函数

    📖 默认成员函数 用户没有显式实现,编译器会自动生成的成员函数,称为默认成员函数。 构造函数 :完成对象的初始化工作。 析构函数 :完成对象空间的清理工作。 拷贝构造 :使用同类对象初始化创建对象。 赋值重载 :把一个对象赋值给另外一个对象(该对象已存在

    2024年02月16日
    浏览(44)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包