如何在不破坏移动和复制构造函数的情况下声明虚拟析构函数

Posted

技术标签:

【中文标题】如何在不破坏移动和复制构造函数的情况下声明虚拟析构函数【英文标题】:How to declare the virtual destructor without breaking move and copy constructors 【发布时间】:2016-05-09 17:33:29 【问题描述】:

当向这样的类添加用户定义的默认虚拟析构函数时..

class Foo

public:
    Foo();
    virtual ~Foo() = default;
;

.. 它具有防止自动生成移动构造函数的副作用。也不推荐使用自动生成复制构造函数。 A recommended way is to user define all constructors 像这样..

class Foo

public:
  Foo();
  virtual ~Foo() = default;
  Foo(const Foo& /* other */) = default;
  Foo&operator=(const Foo& /* other */) = default;
  Foo(Foo&& /* other */) = default;
  Foo&operator=(Foo&& /* other */) = default;
;

但是,这非常冗长且难以阅读。有没有其他解决方案?

【问题讨论】:

如果您有一个虚拟 dtor,您可能希望删除所有复制和移动 ctor。 并且可能有一个clone() 方法来代替。 我认为您希望所有类中的最后四行无论如何(可能使用= delete 而不是= default) - 只是为了清楚类正在提供。 (可以说,如果你删除了“复制”功能,则无需提及“移动”功能。) @MartinBonner 我认为所有最后的行都应该避免如果可能的话。通过 raii 设计,这几乎总是可能的。到处复制五行样板代码并不能增加清晰度。但是,如果您添加一个,则添加其余的! 【参考方案1】:

首先我会考虑Foo 是否真的需要一个虚拟析构函数。也许您可以使用简单的模板以类型安全的方式解决您的问题,从而避免弄乱指针和强制转换等。

如果您决定将Foo 设为虚拟,那么我会推荐这种抽象。

class VirtualDestructor

protected:
  VirtualDestructor() = default;
  virtual ~VirtualDestructor() = default;
  VirtualDestructor(const VirtualDestructor & /* other */) = default;
  VirtualDestructor &operator=(const VirtualDestructor & /* other */) = default;
  VirtualDestructor(VirtualDestructor && /* other */) = default;
  VirtualDestructor &operator=(VirtualDestructor && /* other */) = default;
;

将其放入适当的namespace 的库中。然后你可以保持Foo 和所有其他虚拟类干净。

class Foo : VirtualDestructor

public:
    Foo();
;

删除复制构造函数时也可以使用相同的技术。

编辑: Compiler output 和 diff with original code

【讨论】:

您能否详细说明Foo 直接在其中包含这些= default 定义时的行为以及从VirtualDestructor 继承它们时的行为的差异(如果有)?跨度> @einpoklum 用两个版本的编译器输出更新了答案。 虚拟析构函数不会抑制operator=,所以我建议从你的类中删除它们(你的选择对派生类施加了条件,例如他们可能想要使用复制和交换)

以上是关于如何在不破坏移动和复制构造函数的情况下声明虚拟析构函数的主要内容,如果未能解决你的问题,请参考以下文章

5 规则(用于构造函数和析构函数)过时了吗?

使用 requires 的可选非平凡析构函数

为啥微不足道的复制/移动可构造性取决于微不足道的可破坏性?

[类和对象]构造和析构

c++ 接口必须遵守五法则吗?

C++——构造函数析构函数以及复制构造函数