I am studying policy based design from Modern C++ Design, and I have got stuck in a simple example below, where I was trying to use a std::vector
of std::unique_ptr
s in my templated policy class:
#include <memory>
#include <vector>
template <class T> struct MyPolicy {
MyPolicy() = default;
MyPolicy(std::size_t N) : myvec{std::vector<std::unique_ptr<T>>(N)} {
for (std::size_t i = 0; i < N; i++)
myvec[i].reset(new T(i));
}
// protected: // or, even, public:
// /*virtual*/ ~MyPolicy() = default;
private:
std::vector<std::unique_ptr<T>> myvec;
};
template <class T, template <class> class Policy>
struct Shell : public Policy<T> {
Shell() = default;
Shell(std::size_t N) : Policy<T>(N) {}
};
int main(int argc, char *argv[]) {
Shell<double, MyPolicy> s;
s = Shell<double, MyPolicy>(7);
Shell<double, MyPolicy> s2{6};
s = std::move(s2);
return 0;
}
Everything works well above. However, the catch is that since MyPolicy
is supposed to be inherited from, its destructor needs to be either virtual
and public
, or non-virtual
and protected
(at least, quoting from the book).
In the above example, whenever I uncomment the lines to make them either
public:
virtual ~MyPolicy() = default;
or
protected:
~MyPolicy() = default;
the code does not compile. I cannot understand what the problem related to std::unique_ptr
is in this example, since the type T
is not incomplete or something that has a protected/private destructor.
I would appreciate your help. Thanks.
Declaring a destructor prevents the move constructor and move assignment operators from being implicitly declared. As such, if you declare a virtual destructor and want the default special move functions, you need to explicitly declare them yourself:
public:
virtual ~MyPolicy() = default;
MyPolicy(MyPolicy&&) = default; //here
MyPolicy& operator= (MyPolicy&&) = default; //and here