默认析构函数做什么吗?

时间:2013-02-16 12:17:59

标签: c++ destructor

我想知道默认类析构函数在被调用时是否实际执行了任何操作。

我一直在研究它,我发现如果我创建一个带有调用自己的析构函数的函数的类,它根本不做任何事情(即所有变量保持不变,实例仍然存在且可用)

这是否意味着类析构函数可以被认为是所有类都具有的继承虚函数,并且可以重新定义它(删除指针等并清除成员变量)但是如果它没有重新定义它什么都不做?

如果是这样,析构函数本身不能用作“清除所有数据”类型的函数,并通过清除动态内存分配变量并重新使用它而不是让计算机到达而使代码的某些部分更有效在堆上找到一个新的内存块?

感谢。

4 个答案:

答案 0 :(得分:2)

  • 默认构造函数调用所有成员变量的默认构造函数,不包括基本类型(char,int,pointers)。
  • 可以显式调用析构函数,但这并不意味着对象的取消定位。如果对象在堆栈上,则它不可能对它做任何事情。
  • 默认情况下,析构函数不是虚拟的,但如果您打算继承该类,它们确实应该是。
  • 如果对象被解除分配(超出范围,从堆中删除,或者通过任何方式取消封闭对象),将调用该desctuctor。

答案 1 :(得分:2)

  

我一直在研究它,我发现如果我创建一个带有调用自己的析构函数的函数的类,它根本不做任何事情(即所有变量保持不变,实例仍然存在且可用)

考虑以下代码:

#include <iostream>

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

struct B
{
    A a;
};

int main()
{
    B b;
    std::cout << "Calling b.~B()" << std::endl;
    b.~B();
    std::cout << "Done" << std::endl;
}

You'll see调用B的默认析构函数调用A的析构函数,因为B包含A

Calling b.~B()
A::~A
Done
A::~A

只有当b超出范围时,堆栈才会被解除,合并的B::~B()会被调用,反过来,A::~A()会被释放。

答案 2 :(得分:1)

除了Notinlist的回答:

默认构造函数调用基类的构造函数。

  

如果是这样,析构函数本身不能用作“清除所有数据”   一种功能,使代码的某些部分更有效率   清除动态内存分配变量并重新使用它   而不是让计算机在上面找到新的内存块   堆?

您有点描述内存池。如果需要,您的对象可以从您创建的某个池系统中获取内存缓冲区并将其返回。但是,在大多数情况下,分配足够快且不经常,以至于人们不再常见(不再)这样做。并不是说它们很少发生,但它们需要发生很多以注意到性能损失。

答案 3 :(得分:1)

手动调用析构函数通常是一个坏主意。关于destructors的C ++ FAQ部分有很多关于此的信息。

如果您确实想要显式地销毁对象,可以使用其他范围来安全地调用析构函数(请参阅此常见问题解答entry)。此方法还会阻止您使用已销毁的对象实例。虽然实例似乎可以使用,但实际上并非如此。

如果您打算释放某个类实例所拥有的部分资源,而不是全部资源,那么您可以尝试两件事:

  • 在班级上定义clear()(或类似)方法。
  • 确保在调用clear()后保持类的不变量。

假设您手动调用析构函数的初始方法有效,或者您选择执行类似上述clear()方法的操作,在这两种情况下,您可能会在以后遇到问题。

C ++中一个经过充分理解和经常实践的资源管理方法是资源获取初始化(通常缩写为RAII,但如果令人困惑则忽略该名称,这个概念是可以理解的)。有关有用的信息,请参阅this维基百科文章或此answer

这是tl; dr虽然:

  • 资源的生命周期应始终与生命周期相关联 一个对象。
  • 当构造函数完成时,对象的生命周期开始
  • 当析构函数完成时,对象的生命周期结束。

遵循这个习惯用法通常会在C ++资源管理出现之前阻止它们。