5

When adding a user defined default virtual destructor to a class like this..

class Foo
{
public:
    Foo();
    virtual ~Foo() = default;
};

.. It has the side effects of preventing auto generation of move constructors. Also auto generation of copy constructors is deprecated. A recommended way is to user define all constructors like this..

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;
};

However, this is super verbose and unreadable. Are there any other solutions to this?

Community
  • 1
  • 1
Mathias
  • 1,446
  • 2
  • 16
  • 31
  • 1
    If you have a virtual dtor, you probably want to **delete** all copy and move ctors anyway. – n. m. could be an AI Feb 01 '16 at 10:15
  • And potentially have a `clone()` method instead. – Jarod42 Feb 01 '16 at 10:36
  • I would argue that you want those last four lines in all classes *anyway* (possibly with `= delete` rather than `= default`) - just to be clear about what the class is providing. (Arguably if you delete the "copy" functions, you don't need to mention the "move" functions.) – Martin Bonner supports Monica Feb 01 '16 at 10:58
  • @MartinBonner I think all the last _five_ last lines should be avoided _if at all possible_. By raii design that is almost alway possible. Duplicating five lines of boilerplate all over the place do not add to clarity. But if you add one, then add the rest! – Mathias Feb 01 '16 at 11:57

1 Answers1

5

First I would consider whether Foo really needs a virtual destructor. Maybe you can solve your problem in a type safe manner using a simple template, saving you from messing with pointers and casting and so on.

If you decide on making Foo virtual, then I would recommend this abstraction.

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;
};

Put this in a library in an appropriate namespace. Then you can keep Foo and all other virtual classes clean.

class Foo : VirtualDestructor
{
public:
    Foo();
};

The same technique can also be used when deleting for example copy constructors.

Edit: Compiler output and diff with original code

Mathias
  • 1,446
  • 2
  • 16
  • 31
  • Can you elaborate on the difference, if any, in the behavior of `Foo` when having these `= default` definitions directly in it, and its behavior when it inherits them from `VirtualDestructor`? – einpoklum Feb 01 '16 at 10:04
  • @einpoklum Updated answer with compiler output of the two versions. – Mathias Nov 21 '16 at 13:29
  • virtual destructor does not suppress `operator=` so I would suggest removing those from your class (your choices impose a condition on derived classes, they might have wanted to use copy-and-swap for example) – M.M Nov 21 '16 at 13:30