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() = defau
That comment is wrong.
Instead of providing your own move constructor, if you want the compiler to provide one, one of the requirements is that it expects that the destructor is also provided by it i.e. a trivial destructor. However, the current standard is pretty strict on when an implicit implementation can be provided — in accepting how a destructor is given by the user. Anything declared by the user is considered that the user is taking the matter into their own hands and thus not only this
~A() { … }
but also this
~A() = default;
makes the compiler not provide an implicit destructor. First is a definition and thus a declaration too; second is just a declaration. In both cases the destructor is user-declared and thus prohibits the compiler from providing an implicit move constructor.
I guess the rationale behind the requirement is that during move an object's resources are moved to another object leaving the original object in a state where it has no resources in dynamic-storage; but if your class doesn't have any such resources then it can be trivially moved, destroyed, etc. When you declare a non-trivial destructor it's a cue for the compiler that the resources you manage in the class are not something trivial and that you'd mostly have to provide non-trivial move too, so the compiler doesn't provide one.
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.
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 default
ed, 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
}
}
+ 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 classX
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.
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.