2
votes

http://en.cppreference.com/w/cpp/language/rule_of_three

I have begun with c++11 a couple of months ago and have watched the rule of five.

So.. I started putting copy constructor/copy assignment operator/move constructor/move assignment operator with default keyword on every class having virtual destructor.

because the rule told me that if you declare explicit destructor then your class doesn't have its implicit move constructor and move assignment operator anymore.

So I think gcc is going to complain to me that below class due to lack of move constructor and move assignment operator.

But It works well! What happend??

class Interface {
public:
    virtual ~Interface() = default;  // implicit destructor
};

class ImplA : public Interface {
public:
    virtual ~ImplA() = default; // implicit destructor
};

ImplA first;
ImplA second(first);            // copy constructor, OK. understood it.
ImplA third(std::move(first));  // move constructor, it's OK. Why?
second = first;             // copy assignment, OK. understood it.
second = std::move(first);  // move assignment, it's also OK. Why?
1
Take a look at move ctor, section "Deleted implicitly-declared move constructor", your class does not satisfy any condition listed there. - YiFei
Everything is ok. th =default destructor is equivalent to the implicit one, so those classes do not count as having user-defined destructor as mentioned in the rule of 5. - K. Kirsz
The rule of 5 is a guideline. It's because it's often needed, not because you should always do it. If your virtual destructor only exists to make your type polymorphic (as is the case in your example), then there is no need to create the other methods, because of that. - xaxxon
@K.Kirsz That contradicts what is stated in the reference (and the C++ standard.) - juanchopanza
@jay Your destructor is not user-provided but still user-declared; that means no move constructor and assignment operator will be implicitly-declared by the compiler. See the section "Implicitly-declared move constructor" of the link. - songyuanyao

1 Answers

5
votes

So I think gcc is going to complain to me that below class due to lack of move constructor and move assignment operator.

Because the operations required could be performed via copy constructor and copy assignment operator. Interface still has copy constructor and copy assignment operator which are implcitly declared. And rvalues are always possible to be bound to const Interface&.

More precisely, even without move constructor and move assignment operator provided, Interface is still MoveConstructible,

A class does not have to implement a move constructor to satisfy this type requirement: a copy constructor that takes a const T& argument can bind rvalue expressions.

and MoveAssignable.

The type does not have to implement move assignment operator in order to satisfy this type requirement: a copy assignment operator that takes its parameter by value or as a const Type&, will bind to rvalue argument.


BTW: If you make the move constructor and move assignment operator delete explicitly then both copy and move operation would fail. Using with an rvalue expression the explicitly deleted overload will be selected and then fails. Using with an lvalue expression would fail too because copy constructor and copy assignment operator are implicitly declared as deleted because of the declaration of move constructor or move assignment operator.