Why do we need to use virtual ~A() = default; instead of virtual ~A() {} in C++11?

In Stack Overflow post Checking the object type in C++11, I have the comment:

In C++11 you'll actually want to do virtual ~A() = default; Otherwise, you'll lose the implict move constructors.

What is virtual ~A() = default; for? How come implicit move constructors lost with virtual ~A() {}?


Solution 1:

The comment is not correct.

Both:

virtual ~A() = default;

and

virtual ~A() {}

are user declared. And the implicit move members are inhibited if the destructor is user declared.

[dcl.fct.def.default]/p4 discusses user-declared and user-provided special members:

A special member function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration.

Solution 2:

In this post https://stackoverflow.com/a/17204598/260127, I have the comment:

In C++11 you'll actually want to do virtual ~A() = default; Otherwise, you'll lose the implict move constructors.

The comment is incorrect.

Even defaulted, that destructor is "user-declared" (though note that it is not also "user-provided").

#include <iostream>

struct Helper
{
    Helper() {}
    Helper(const Helper& src) { std::cout << "copy\n"; }
    Helper(Helper&& src)      { std::cout << "move\n"; }
};

struct A
{
    virtual ~A() {}
    Helper h;
};

struct B
{
    virtual ~B() = default;
    Helper h;
};

struct C
{
    Helper h;
};


int main()
{
    {
        A x;
        A y(std::move(x));   // outputs "copy", because no move possible
    }

    {
        B x;
        B y(std::move(x));   // outputs "copy", because still no move possible
    }

    {
        C x;
        C y(std::move(x));   // outputs "move", because no user-declared dtor
    } 
}

Live demo:

+ g++-4.8 -std=c++11 -O2 -Wall -pthread main.cpp
+ ./a.out
copy
copy
move

So you haven't "lost" anything — there was no move functionality there to begin with!

Here is the standard passage that prohibits an implicit move constructor in both cases:

[C++11: 12.8/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.

Bootnote

It wouldn't hurt if a future version of the standard actually listed the precise meanings of terms such as "user-declared". There is, at least, this:

[C++11: 8.4.2/4]: [..] A special member function is user-provided if it is user-declared and not explicitly defaulted or deleted on its first declaration. [..]

One may assume the distinction here by implication.