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

When to make a destructor defaulted using =default?

提问人:TonySalimi 提问时间:6/28/2019 最后编辑:TonySalimi 更新时间:3/20/2020 访问量:2828

问:

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

  1. 那些使用 =default
  2. 那些没有显式定义并由编译器自动生成的那些。

我唯一想到的是,group-1 析构函数可以定义为虚拟的,但 group-2 始终是非虚拟的。那么,这是它们之间的唯一区别吗?是否有任何情况是编译器没有生成析构函数,但使用 =default 强制编译器生成它?

p.s. 我在 stackoverflow 中检查了很多 Q,但没有一个回答我的 Q。以下是一些相关问题。

  1. =default 和 {} ctos/destructors 之间的区别
  2. 默认虚拟析构函数
  3. =default 和空 dtrs 之间的区别

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

C++ C++11 析构函数

评论

0赞 David G 6/28/2019
默认虚拟或纯虚拟析构函数是我所知道的仅有的两种适用情况。
5赞 M.M 6/28/2019
析构函数本身的行为与省略它的行为相同;但是声明的存在会抑制 move-constructor 和 move-assignment 的隐式生成= default
3赞 Ted Lyngmo 6/28/2019
编译器隐式生成的那些类型将需要完整的类型,这在创建类时是不可能的。然后,您可以在类型完成后在实现中声明 and do。pimpl~X();~X() = default;pimpl
1赞 Nevin 6/28/2019
其他情况:您希望成功或.您希望将其放在 .cpp 文件中,以便它不会内联。protectedprivate
1赞 TonySalimi 6/28/2019
@Aconcagua 我认为主要区别在于使用 =default 或 {} 时是微不足道的和非微不足道的,如以下答案所述:stackoverflow.com/a/13578720/896012

答:

10赞 Davis Herring 6/28/2019 #1

(以下几点已经在评论或链接的问题中提到过;这个答案有助于组织和相互关联。

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

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

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

与主要区别很简单:显式默认的析构函数可能微不足道。仅当它在类内默认时才适用,因此在行外定义和 之间没有区别。同样,虚拟消除了任何区别,就像任何成员或基类都具有非平凡的析构函数一样。还有一个区别是,显式默认的析构函数可以隐式定义为已删除。这两个属性都与隐式声明的析构函数共享,因此我们也必须找到与这些属性的区别。Empty{}=default;

与 相比,显式默认的析构函数抑制移动操作,可以声明 、 或 noexcept(false),并且在 C++20 中可以约束(但不能)。非常微不足道,可以声明以验证它无论如何都会。声明它不会做任何事情。(它也可以是不合时宜的或虚拟的,但如上所述,这不能成为使用它的理由。Implicitprivateprotectedconstevalconstexprinline

因此,答案是“当您想要一个具有其他特殊属性的琐碎(或可能被删除)的析构函数时”——最有用的是访问控制或状态。noexcept