Reputation: 3307
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?
Upvotes: 40
Views: 6130
Reputation: 27
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:
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.Upvotes: -1
Reputation: 65640
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.
Upvotes: 34