【问题标题】:What are defaulted destructors used for?默认析构函数是做什么用的?
【发布时间】:2015-07-28 09:20:48
【问题描述】:

我可以理解默认构造函数,因为用户定义的构造函数将禁用编译器生成的构造函数,从而使对象不可复制等。

在析构函数的情况下,除了更改访问类别之外,考虑到没有用户定义的成员函数可以禁用它们(你不能重载析构函数),定义默认析构函数有什么用?

// Which version should I choose ? 
struct Example 
{
    //1. ~Example() = default; 
    //2. ~Example() {}
    //3. 
}; 

即使在虚拟析构函数的情况下,默认它们也不会使它们变得微不足道,那么这样做有什么好处?

【问题讨论】:

  • 反对者愿意解释吗?这似乎是一个非常有效的问题。
  • @legends2k 我相信他们和here有同样的理由......根本没有:P

标签: c++ c++14


【解决方案1】:

忽略不重要的析构函数的例外与派生的类的析构函数有关,而不是基类的析构函数。所以virtual ~Foo() = default; 是一个有用的构造,可以保留默认析构函数,但要对其进行虚拟化。

【讨论】:

  • 是的,但这与virtual ~Foo() {} 有何不同。由于它们是虚拟的,所以它们都不是微不足道的,那么这里有什么好处呢?
  • @NikosAthanasiou 好点。我猜想一致性和意图清晰。
  • @NikosAthanasiou 统一?就像 Foo() {}Foo() = default w.r.t 构造函数一样。
  • @legends2k Foo() {} 是用户提供的,因此不是微不足道的,因此它与Foo() = default 不同,Foo() = default 等同于隐式定义一个(微不足道的)。可以通过在任何适当对齐的存储上使用 reinterpret_cast 创建具有琐碎默认构造函数的对象,例如在用std::malloc 分配的内存上。所有与 C 语言兼容的数据类型(POD 类型)都可以简单地默认构造。
  • @NikosAthanasiou 啊,我的错!在这种情况下,标准说 user-provided 而不是 user-declared 就像它对 ([class.copy]) 隐式移动所做的那样构造函数(see here)。我忽略了这种差异。
【解决方案2】:

一种用途是使用析构函数protectedprivate,同时可能使类保持简单:只需将其列在所需的访问说明符之后。

另一个:在编写类时,一些程序员喜欢对类的函数进行排序:例如构造函数,然后是析构函数,然后是非const“变异”成员,然后是const“访问器”成员,然后是static函数。通过能够显式地= default 析构函数,您可以按预期的顺序列出它,并且查看那里的读者知道不可能有另一个放错位置的版本。在大型课程中,这可能具有一定的记录/安全价值。

它还为您提供了添加 cmets 的具体内容,这可以帮助一些文档工具实现 cmets 与销毁相关。

【讨论】:

    【解决方案3】:

    基本上它是关于传达意图,但相当多余。

    但如果您使用std::unique_ptr 作为类的成员,您需要在标题中声明析构函数(但仅声明)。然后你可以让它在源文件中使用默认实现,如下所示:

    MyClass:~MyClass() = default;
    

    考虑到您的选择,我会使用第一个或第三个。

    【讨论】:

      【解决方案4】:

      正如Nikos Athanasiou 在评论中提到的那样,默认构造函数使该类型可以简单地破坏,而用户定义的则不能。一个小代码示例将显示它:

      #include <iostream>
      #include <type_traits>
      
      struct A { ~A() = default; };
      struct B { ~B() {} };
      struct C { ~C() noexcept {} };
      
      int main() {
        std::cout
          << std::is_trivially_destructible<A>::value
          << std::is_trivially_destructible<B>::value
          << std::is_trivially_destructible<C>::value
          << std::endl;
        return 0;
      }
      

      显示

      100
      

      至于虚拟析构函数,与非虚拟析构函数的一致性和Quentin 的回答是恰当的理由。我个人的建议是,你应该尽可能使用默认值,因为这是坚持最规范行为的一种方式。

      【讨论】:

      • 我的评论是关于默认构造函数并且可以简单构造。我赞成,因为答案有助于实现完整性,但我的问题断言,没有任何情况下省略析构函数与默认析构函数不同,因为用户定义的成员函数不会禁用隐式析构函数。除此之外,虚拟析构函数绝不是微不足道的(无论您是否默认它)
      猜你喜欢
      • 1970-01-01
      • 2012-04-14
      • 2013-02-01
      • 2011-09-30
      • 2022-01-09
      • 2017-11-26
      • 2015-02-04
      • 1970-01-01
      • 2011-06-17
      相关资源
      最近更新 更多