何时使用 =default 使析构函数默认?

When to make a destructor defaulted using =default?

虽然对构造函数使用 =default 对我来说很清楚(即强制编译器在其他构造函数存在时创建默认构造函数),但我仍然无法理解这两种类型的析构函数之间的区别:

  1. 那些使用 =default
  2. 那些没有明确定义的,由编译器自动生成的。

我唯一想到的是group-1的析构函数可以定义为virtual,但是group-2总是非virtual的。那么,这是它们之间唯一的区别吗?是否存在编译器未生成析构函数但使用 =default 强制编译器生成析构函数的情况?

p.s。我在 Whosebug 中检查了很多问题,但其中 none 回答了我的问题。以下是一些相关问题。

  1. Difference between =default and {} ctos/destructors
  2. Defaulting virtual destructors

编辑 1: 在 SO 上,着重于禁用默认的移动构造函数,这可以被视为接受的答案中提到的项目之一。

(评论或链接问题中已经提到了以下几点;此答案用于组织和相互关联它们。)

当然有三种方法可以得到一个“简单的析构函数”:

struct Implicit {};
struct Empty {~Empty() {}};
struct Defaulted {~Defaulted()=default;};

与默认(而不是复制或移动)构造函数一样,{}=default; 对析构函数的含义大致相同。 Defaulted 的有趣属性是那些(组合)不同于其他 both 的那些(组合)。

Empty 的主要区别很简单:显式默认的析构函数可以是 微不足道的 。这仅适用于在 class 中默认设置的情况,因此 out-of-line 定义中的 {}=default; 没有区别。类似地,虚拟消除了任何区别,就像让任何成员或基 class 具有 non-trivial 析构函数一样。还有一个区别是显式默认的析构函数可以隐式 defined as deleted。这两个属性都与隐式声明的析构函数共享,因此我们也必须找到它们的区别。

Implicit 相比,显式默认的析构函数抑制移动操作,可以声明为 privateprotectednoexcept(false),并且在 C++20 中可以是约束(但不是 consteval)。非常勉强地,它可以被声明为 constexpr 以验证它无论如何都会是。声明它 inline 不会做任何事情。 (它也可以是越线或虚拟的,但如上所述,这不能成为使用它的理由。)

所以答案是“当你想要一个具有其他特殊属性的微不足道的(或可能被删除的)析构函数时”——最有用的是访问控制或 noexcept 状态。