I am trying to find out why in the following example, when I disable copy-semantics but preserve move-semantics, emplacing into std::vector works in one case but does not work in another (when inheritance is used):
#include <iostream>
#include <vector>
class NonCopyable
{
public:
NonCopyable(const NonCopyable &) = delete;
NonCopyable(NonCopyable &&) noexcept = default;
NonCopyable &operator=(const NonCopyable &) = delete;
NonCopyable &operator=(NonCopyable &&) noexcept = default;
NonCopyable() = default;
virtual ~NonCopyable() = default;
};
// NOTE: here things works as long as I dont override the destructor. If I do, it stops.
class MyClass : public NonCopyable
{
public:
MyClass() = default;
// NOTE: when commented out, all compiles fine, otherwise not
~MyClass() override {}
};
// NOTE: when all is put into a single class, everything compiles ok
class MyClass2
{
public:
MyClass2() = default;
~MyClass2() noexcept
{
}
MyClass2(const MyClass2 &) = delete;
MyClass2 &operator=(const MyClass2 &) = delete;
MyClass2(MyClass2 &&) noexcept = default;
MyClass2 &operator=(MyClass2 &&) noexcept = default;
};
int main()
{
std::vector<MyClass> mc;
MyClass a;
mc.emplace_back(std::move(a));
std::vector<MyClass2> mc2;
MyClass2 a2;
mc2.emplace_back(std::move(a2));
}
Example in online compiler: https://onlinegdb.com/UTWju9WkU
What do I miss ? Thanks!
The rule of 5 states that if you touch any of the 5 special member functions (copy ctor, copy assign, move ctor, move assign, dtor) you should touch them all. Not doing so is a bad plan. (The rule of 5 is also known as the rule of 3, from back before move operations existed).
In this case, when you implement
~MyClass()the compiler no longer synthesizes your move constructor. The move constructor is needed toemplace_back, because it is used if the vector is resized.The standard has the exact rules, but you don't need to memorize them. You should just remember the rule of 5.
(The other rule to know here is the rule of 0 -- don't touch them unless you are writing a resource-management class. And if you are writing a resource-management class, it should just do resource management; use composition to store the resource in your business logic class. Then your business logic class follows the rule of 0, and gets its move/copy/destruction semantics from its members.)