Does a default virtual destructor prevent compiler-generated move operations?
Asked Answered
E

2

40

Inspired by the post Why does destructor disable generation of implicit move methods?, I was wondering if the same is true for the default virtual destructor, e.g.

class WidgetBase // Base class of all widgets
{
    public:
        virtual ~WidgetBase() = default;
        // ...
};

As the class is intended to be a base class of a widget hierarchy I have to define its destructor virtual to avoid memory leaks and undefined behavior when working with base class pointers. On the other hand I don't want to prevent the compiler from automatically generating move operations.

Does a default virtual destructor prevent compiler-generated move operations?

Extort answered 27/11, 2015 at 12:4 Comment(0)
S
34

Yes, declaring any destructor will prevent the implicit-declaration of the move constructor.

N3337 [class.copy]/9: If the definition of a class X does not explicitly declare a move constructor, one will be implicitly declared as defaulted if and only if

  • X does not have a user-declared copy constructor,
  • X does not have a user-declared copy assignment operator,
  • X does not have a user-declared move assignment operator,
  • X does not have a user-declared destructor, and
  • the move constructor would not be implicitly defined as deleted.

Declaring the destructor and defining it as default counts as user-declared.

You'll need to declare the move constructor and define it as default yourself:

WidgetBase(WidgetBase&&) = default;

Note that this will in turn define the copy constructor as delete, so you'll need to default that one too:

WidgetBase(const WidgetBase&) = default;

The rules for copy and move assignment operators are pretty similar as well, so you'll have to default them if you want them.

Segmentation answered 27/11, 2015 at 12:12 Comment(3)
Apparently a user-defined virtual destructor would not delete the move operations. See: coliru.stacked-crooked.com/a/b95b6bb23630755fVargas
@Vargas I think compilers are not implementing this rule?Outwit
actually: #51902337Outwit
M
-1

Not a solution, but one of possible workarounds. You can inherit all of your classes from a class that has only default virtual destructor.

I checked using GCC 9 and Apple's Clang++ with -std=c++17: both of them generate move constructors for classes that inherit the class below.

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

The class below will indeed have a move constructor.

class Child : public Object {
public:
    Child(std::string data) : data(data) {
    }

private:
    std::string data;

};

Another possible but risky workaround would be to not declare virtual destructors at all. It would introduce the following risks:

  • All objects must always be destructed by someone who knows their exact type. Which is not really that big of a problem in a nicely designed C++ code.
  • When object of such class is stored in a container like std::vector or std::list it must always be wrapped using std::shared_ptr. std::unique_ptr would cause leaks! That's related to their differences related to storing deleter.
Markman answered 12/7, 2019 at 17:56 Comment(2)
I have been trying to figure out your first suggestion for a while.... So I think it says: the base class will not get a move c'tor, but the derived class will (because it does not have a virtual d'tor of its own)? - thanks for confirming :)Unknowing
This doesn't answer the question and isn't really useful informationHighsmith

© 2022 - 2024 — McMap. All rights reserved.