【问题标题】:When do I need to declare my own destructor?我什么时候需要声明自己的析构函数?
【发布时间】:2014-08-01 18:57:13
【问题描述】:
class Point    
{
public:
    float x,y;
    Point() {}
    Point(float,float);
    Point operator + (Point);
    Point operator * (double);
    void rotate_p(float);
    void render_p(Point*);
    void sub(float);
    float get_dist();//get_distance
};

你可以看到这个类没有指针作为非静态 数据成员,所以我想我可以使用默认的析构函数;这准确吗?


问题

  • 什么时候需要声明自己的析构函数?

【问题讨论】:

  • 不,您不需要提供析构函数,但您可能需要确保 xy 在默认构造函数中初始化为零。
  • 请注意,这不是当你有指针的时候。当对象被破坏时,您需要清理某些东西或以其他方式做某事。当您使用拥有资源的原始指针时,通常会发生这种情况。
  • 如果你想从Point继承并在Point* p指针中存储派生类型的堆分配对象,你需要定义一个虚拟析构函数。否则,在删除p 时不会调用派生对象的析构函数。并且可能在派生对象中管理了一些内存。
  • @Tobias 严格来说,您需要虚拟析构函数通过指向基类的指针对派生类型对象调用 delete。
  • @juanchopanza 更好:...通过指向基类的指针调用派生类型对象上的析构函数

标签: c++ class destructor


【解决方案1】:

简介

由于具有自动存储持续时间的数据成员的生命周期与拥有它们的实例的生命周期绑定,因此您无需显式调用它们的析构函数;只要类的实例存在,它们就会被销毁。


我通常什么时候需要声明自己的析构函数?

通常,如果出现以下情况,您必须显式声明自己的析构函数:

  • 您正在声明一个类,该类应该用作涉及多态性的继承的基础,如果这样做,您将需要一个 虚拟析构函数 以确保 Derived 类在通过指向 Base 的指针/引用销毁它时被调用。

  • 你需要释放该类在其剩余时间内获得的资源

    • 示例1:该类有一个文件句柄,当对象析构时需要关闭该句柄;析构函数是完美的位置。

    • 示例 2:该类拥有一个具有动态存储持续时间的对象,因为该对象的生命周期可能在类实例具有已被销毁,您需要在析构函数中显式销毁它。


隐式生成的析构函数

除非您明确声明自己的析构函数,否则编译器将为您创建隐式生成的析构函数。

14.4p4 析构函数 [class.dtor]

如果一个类没有用户声明的析构函数,析构函数是 隐式声明为默认值 (8.4)。隐式声明 析构函数是其类的内联公共成员。

src:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf


然而,在一些罕见/高级情况下,编译器会拒绝为您生成析构函数,在这些情况下,您必须显式声明自己的析构函数,或者确保为您的类实例生成析构函数永远不会被调用;因为要销毁一个对象,就需要一个析构函数。

14.4p5 析构函数 [class.dtor]

类 X 的默认析构函数定义为 delete if:

  • X 是一个类联合类,它有一个变体成员 析构函数,

  • 任何非静态数据成员都有类类型 M(或数组 其中)和 M 有一个已删除的析构函数或一个析构函数 无法从默认析构函数访问,

  • 任何直接或虚拟基类都具有已删除的析构函数或 无法从默认析构函数访问的析构函数,

  • 或者,对于虚拟析构函数,查找非数组释放 函数导致歧义或函数被删除 或无法从默认析构函数访问。

src:http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf


更多内容可点击以下链接阅读:

【讨论】:

    【解决方案2】:

    析构函数的主要目的是从堆中释放已使用的内存或删除指向其他对象的链接等。这里不从堆中分配内存,也不在对象之间建立任何关系,因此不需要析构函数。

    【讨论】:

      【解决方案3】:

      您可能还想查看“三法则” 三法则(也称为三巨头法则或三巨头法则)是 C++ 中的一条经验法则,它声称如果一个类定义了以下其中一项,它可能应该明确定义所有三项:

      析构函数, 复制构造函数, 复制赋值运算符, 维基百科链接:http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)

      【讨论】:

        【解决方案4】:

        如果在编译时计算内存(即在运行时不分配内存),则可以创建析构函数,但这不是必需的。在这种情况下,类的定义隐含了类的析构函数;将在幕后为您提供析构函数,并且当类的实例超出范围时将释放内存。

        编辑:可以在这里找到一个简单、方便的教程 - http://www.learncpp.com/cpp-tutorial/86-destructors/

        【讨论】:

          【解决方案5】:
          • 虽然如果你不定义一个,语言会为你定义一个析构函数。

          • 通常,将析构函数定义为virtual 是一个好主意,以确保如果有人从您的类继承,一切都会好起来的。

          • 但是,如果您在构造函数中动态分配内存,则必须定义析构函数,并确保将删除其中的所有已分配内存,以避免内存泄漏。

            李>
          • 另一个建议是,如果您的编译器支持 C++11 功能,最好避免在内存分配中使用原始指针并使用智能指针(即 RAII)。因此,您不必删除析构函数中任何先前分配的内存。

          【讨论】:

            【解决方案6】:

            析构函数是在对象被销毁时执行的代码……句号。

            析构函数中的内容取决于与对象关联的语义。

            典型的东西在析构函数中(但可能在其他地方,例如考虑一个池化对象)是

            1. 释放对象当前拥有的所有内存(请注意,它可能已分配内存但转移了其所有权)。
            2. 释放对象已获取的所有资源。
            3. ....

            例外是您必须声明一个虚拟析构函数,即使在类层次结构中为空,您也需要能够从指向父类的指针中销毁子类的对象。

            如果您没有定义一个析构函数,编译器将为您提供一个默认析构函数。 此外,类中包含的属性将在(隐式/显式)类析构函数运行后自动调用其析构函数。

            【讨论】:

              猜你喜欢
              • 2011-12-13
              • 2014-04-24
              • 2013-09-04
              • 2010-09-21
              • 2019-03-01
              • 2022-01-15
              • 2011-09-20
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多