美文网首页
12-析构函数(Destructor)

12-析构函数(Destructor)

作者: ducktobey | 来源:发表于2019-11-16 17:37 被阅读0次

析构函数(Destructor)

析构函数(也叫析构器),在对象销毁的时候自动调用,一般用于完成对象的清理工作

在前面,已经知道了,如果构造函数被调用,是新对象诞生的象征。与之相反的,如果对象的析构函数被调用,则是对象的内存即将被回收,对象即将被销毁的象征。

析构函数的特点:

函数名以~开头,与类同名,无返回值(void都不能写),无参,不可以重载,有且只有一个析构函数

struct Person {
    Person() {
            cout << "Person::Person()" << endl;
    }
    ~Person() {
        cout << "~Person::Person()" << endl;
    }

};

我们在测试是,可以在main函数中这样进行调用

int main() {
    cout << 1 << endl;
    {
        Person person;
    }
    cout << 2 << endl;

    getchar();
    return 0;
}

通过改变person对象的作用域的话,就可以成功的看到,析构函数被调用了。并且调用的时机是在1与2之间。

注意:通过malloc分配的对象free的时候不会调用析构函数;即通过下面方式分配的对象,在free的时候,不会调用析构函数

int main() {
    Person* p = (Person*)malloc(sizeof(Person));
    free(p);

    getchar();
    return 0;
}

析构函数的作用

前面,知道了析构函数是在对象即将被销毁时,做一些收尾的工作,但是假设类中定义了一些成员变量时,创建的对象被销毁时,一般不需要做任何操作,因为对象销毁时,对象所在的内存空间中,保存的成员变量,也将被回收,例如下列的情况

struct Person {
    int m_age;
    Person() {
        cout << "Person::Person()" << endl;
    }
    ~Person() {
        cout << "~Person::Person()" << endl;
    }
};

上面这种情况,当创建的Person对象销毁时,Person对象中的m_age成员变量,也会自动被回收掉,那么析构函数到底有什么作用呢?

那请看下面这种情况,假设现在Person有一个属性m_car,表示创建出来的每一个Person对象,都有一辆车。

struct Car {
    int m_price;
    Car() {
        m_price = 0;
        cout << "Car::Car()" << endl;
    }
    ~Car() {
        cout << "~Car::Car()" << endl;
    }
};

struct Person {
    int m_age;
    Car* m_car;
    Person() {
        m_age = 0;
        m_car = new Car();
        cout << "Person::Person()" << endl;
    }
    ~Person() {
        cout << "~Person::Person()" << endl;
    }
};

int main() {
    {
        Person person;
    }
    getchar();
    return 0;
}

按照前面的结论,当创建出来的person对象销毁时,person对象中的成员变量也将要被销毁,但是当将这段程序运行起来以后,会发现一个问题,最终打印的结果为

Car::Car()
Person::Person()
~Person::Person()

Car对象中的析构函数没有调用,析构函数没有调用,则说明Car对象没有销毁,那么这段程序存在内存泄漏(内存泄漏:该释放的内存并没有得到释放)的问题,为什么Car对象没有释放呢?先来看看创建出来的对象,在内存中是如何分布的吧!

所以前面的Car对象是通过new出来的,在构造函数章节知道了,new出来的对象,申请的内存空间在堆空间,堆空间的内存不会自动回收,所以当person对象销毁的时候,内存布局是这样的,

所以person对象的自动回收,并不代表堆空间的car对象也会回收。因此需要主动通过delete方式来释放,那么可以在person对象即将被系统回收前,将对象拥有的car也释放掉,所以可以这样来修改

~Person() {
    delete m_car;
    cout << "~Person::Person()" << endl;
}

通过主动调用delete以后,最终car对象被成功释放

Car::Car()
Person::Person()
~Car::Car()
~Person::Person()

析构函数,用来做内存清理工作,清理内部产生的堆空间,例如上面的car对象,是在Person类中new出来的,所以在person对象销毁时,需要将类中new出来的对象也释放掉。

析构函数内存管理分析
情况一

为了充分认知对象的内存管理,再看看一下这几种情况,如果代码是这样的

struct Car {
    int m_price;
};

struct Person {
    int m_age;
    Car m_car;
};
int main() {
    {
        Person person;
    }
    getchar();
    return 0;
}

通过这种方式创建出来的person对象,car对象也在栈里面,内存分布如下,这种情况下的person对象占用8个直接的存储空间

情况二

如果代码修改为这种情况呢?

struct Car {
    int m_price;
};

struct Person {
    int m_age;
    Car m_car;
};
int main() {
    {
        Person *p = new Person();
    }
    getchar();
    return 0;
}

通过这种凡是创建出来的对象,是指针变量p指向了堆空间的一块内存[下图]

情况三

假设现在是代码是这种情况

struct Car {
    int m_price;
};

struct Person {
    int m_age;
    Car *m_car;
    Person() {
        m_car = new Car();
    }
    ~Person() {
        delete m_car;
    }
};
int main() {
    {
        Person *p = new Person();
    }
    getchar();
    return 0;
}

这种情况,稍微复杂一些,不过根据前面的结论,也容易很快的想出来,其内存分布是怎么样的。

相信根据以上分析的几种情况,以后在写出一段代码,创建一个对象,你一定知道这一段代码,创建出来的对象,牵扯到了哪些内存区域,并且每个对象应该存放在哪个位置都是很清楚的了。所以一定要扫除一个误区:指针变量并不是都在栈空间,基本数据类型也不都是在栈空间。

一个变量的内存在哪个区域,取决于内存的申请方式

demo下载地址

文章完。

相关文章

  • 12-析构函数(Destructor)

    析构函数(Destructor) 析构函数(也叫析构器),在对象销毁的时候自动调用,一般用于完成对象的清理工作 在...

  • C++ 从入门到放弃 (Day-06)

    析构函数(Destructor) ◼ 析构函数(也叫析构器),在对象销毁的时候自动调用,一般用于完成对象的清理工作...

  • Swift中的deinit方法

    deinit属于析构函数 析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所在的...

  • C++ 析构函数

    析构函数(destructor)是一种特殊的成员函数。 类的析构函数名是在类名前加一个波浪好~ 累的析构函数是在删...

  • C++面向对象(2)

    类的构造函数(Constructor)和析构函数(Destructor) 构造函数是类的一种特殊的成员函数,它会在...

  • 360笔试题

    1. 在函数F中,本地变量a和b的构造函数(constructor)和析构函数(destructor)的调用顺序是...

  • iOS swift-deinit

    deinit deinit: 析构函数(destructor) 与构造函数相反,当对象结束其生命周期时(例如对象所...

  • 构造函数和析构函数(Destructor)

    在正式介绍析构函数之前, 需要先讲一下构造函数,它是一种特殊的成员函数,主要是用来初始化对象。 构造函数: 特殊的...

  • C++之析构函数

    析构函数的概述 析构函数 完成对象的清理工作,先清理,再释放对象空间。析构函数也是编译器自动调用。 析构函数 不能...

  • 析构函数和标准dispose模式

    析构函数(destructor):可以在一个类的实例不再被引用的时候执行一些操作,以清除或释放非托管资源 注意几点...

网友评论

      本文标题:12-析构函数(Destructor)

      本文链接:https://www.haomeiwen.com/subject/vfnyictx.html