【问题标题】:Destructor in class类中的析构函数
【发布时间】:2013-03-17 05:37:35
【问题描述】:

我创建了一个类,并根据 Andrew Koenig 和 Barbara E. Moo 的教科书 Accelerated C++,

析构函数的工作是在对象消失时进行任何清理。通常,这种清理涉及释放构造函数已分配的资源,例如内存。

我正在尝试编写一个析构函数,但我被所有漂浮在那里的代码弄糊涂了。有时使用像这样的简单解构器~MyIntArray() {},有时{} 之间有一些东西。

在大括号之间放置东西的规则是什么?它只是容器吗?需要放在大括号之间的列表、数组、向量、指针(这些是我在代码示例中看到的内容)。

编辑:这是我的课程,以备不时之需

class msgInfo
{
public:
    msgInfo();
    msgInfo(int, int, int, std::string, std::list<int>);

private:
    int source_id;
    int dest_id;
    int priority;
    std::string payload;
    std::list<int> nodePath;
};

【问题讨论】:

  • 从您的四个(列表、数组、向量和指针)列表中,指针是唯一需要在析构函数中处理的指针。您的班级没有任何这些,因此不需要析构函数。这是一件好事,也是我对阅读 Koenig 和 Moo 的人的期望。

标签: c++ class destructor


【解决方案1】:

好吧,如果您动态分配资源(新等),那么在析构函数中您想要释放它们(删除),在您的情况下,由于您的所有成员都不是动态分配的,因此您的析构函数可以为空(或不存在)。

另一个值得一提的注意事项是,如果您最终实现了析构函数,并且您计划让某人继承您的类,则应该将其设为虚拟。

【讨论】:

  • 如果你没有显式提供析构函数,编译器会提供一个标准的析构函数,所以无论如何它都存在。
  • 只有在你打算派生类时才应该将析构函数设为虚拟,在这种情况下,无论如何你都应该这样做。说您应该始终将其声明为虚拟是个坏建议。
  • 如果你的析构函数是私有的,怎么从分配它的那个人那里删除呢?
  • 至于将析构函数设为虚拟,这里指出了一个风险(cprogramming.com/tutorial/constructor_destructor_ordering.html)
  • @Alon - 可以从朋友类中“删除”,例如 - 当您实现侵入式引用计数智能指针时。
【解决方案2】:

在 C++ 程序中提供析构函数是一种很好的编程习惯,即使没有明确的需要。在您的代码中,您可能没有任何动态内存分配,因此提供的析构函数只是~MyIntArray() {},里面没有任何代码。

另请阅读有关 C++ 中的三法则的 Wikipedia 文章。

http://en.wikipedia.org/wiki/Rule_of_three_(C%2B%2B_programming)

【讨论】:

    【解决方案3】:

    您的类没有任何需要在析构函数中处理的资源:每种类型都是内置的(`int) or handles its own resources (std::string,std::list`)。所以你不需要实现你自己的析构函数。编译器将提供一个与空大括号等效的一个。

    如果您的类有需要处理的资源:动态分配的对象、到套接字的句柄或连接、数据库、引用计数等,您需要实现自己的。

    实现空析构函数可能有意义的一种情况是,当您有一个旨在派生并以多态方式使用的类时。在这种情况下,需要一个虚拟析构函数(有很多关于此的 SO 帖子),并且通常的做法是提供一个空实现,以便派生类型在没有资源需要处理时不必自己实现它。

    virtual ~Foo() {}
    

    【讨论】:

      【解决方案4】:

      如果您不提供析构函数,编译器将为您提供一个。这个自动生成的析构函数会正确调用你类的所有数据成员的析构函数,比如payload等。

      如果您不需要做任何其他事情,那么您不需要显式提供析构函数。或者,一个空的也同样适用。

      另一方面,如果您的构造函数分配了一些资源(例如,连接到数据库),那么通常您需要在析构函数中放入一些代码来释放该资源(例如,断开与数据库的连接)。这是用于防止资源泄漏的standard C++ idiom

      【讨论】:

        【解决方案5】:

        规则 1:

        Rule of three 在 C++03 中或在 C++11 中的五规则。

        如果您的类需要用户定义的复制构造函数或复制赋值运算符,那么它很可能需要用户定义的析构函数。

        你什么时候需要这三个?

        • 当您的类具有动态分配的指针成员并且您需要维护每个独立于另一个实例成员的生命周期时。例如:char * 成员。
        • 当您管理资源时。例如:打开文件句柄、互斥锁等。

        规则 2:

        如果您的类打算用于派生并且您需要多态删除对象,那么您必须将基类中的析构函数标记为virtual

        【讨论】:

          【解决方案6】:

          这样的类不需要一个重要的析构函数(一个,带有“大括号之间的东西”)。

          在析构函数中,您必须释放资源,您已“手动”分配。例如:

          • 如果你在构造函数中有new/new[],你需要在析构函数中释放这块内存
          • 如果你在构造函数中打开了一个文件,在析构函数中关闭它
          • 如果您在构造函数中锁定了一个互斥体,请在析构函数中解锁它

          这样的事情。

          此外,当对象被破坏时,您可能需要实现一些额外的逻辑。取决于你想做什么。

          【讨论】:

            【解决方案7】:

            就我所知或所关心的而言,析构函数的定义应始终如下所示:

            ~msgInfo() { /* free stuff */ }
            

            另一方面,构造函数可能如下所示:

            msgInfo(): m_var1(0), m_var2("Initialize") { /* further initialization */ }
            

            :{ 之间是成员变量初始化。

            在析构函数中,您应该取消分配在类中其他位置动态分配的任何内容,因此: 表示法不好,因为您可能需要对对象执行delete

            【讨论】:

            • OP 没有提到任何关于初始化列表的内容。这里的问题似乎只是将东西放在大括号之间的规则是什么? - 没有提到:
            【解决方案8】:

            在您的代码中,您可能没有任何动态内存分配,因此您不需要提供析构函数。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2017-03-21
              • 2014-05-27
              • 2018-06-29
              • 2016-11-04
              • 2011-05-19
              • 1970-01-01
              • 1970-01-01
              • 2011-09-01
              相关资源
              最近更新 更多