2

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_ptrs 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.

enanone
  • 923
  • 11
  • 25

1 Answers1

3

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

Live demo

TartanLlama
  • 63,752
  • 13
  • 157
  • 193
  • I was checking the example above. Why do you think the example [here](https://godbolt.org/g/UCEnZk) works, even though the move functions are not defined? Would it be possible to modify your answer, accordingly? – Arda Aytekin Jan 23 '18 at 13:27
  • @ArdaAytekin that's using the implicitly-defined copy assignment operator. – TartanLlama Jan 23 '18 at 13:38
  • Oh, I see. Thank you! So basically, if I [delete](https://godbolt.org/g/mCHX7A) them explicitly, which I assume is the case for the `unique_ptr`, then the compiler cannot find a fallback option. Even if I use `std::move`, the compiler is falling back to the copy semantics, then? Thank you very much for your prompt answer, by the way. – Arda Aytekin Jan 23 '18 at 13:46
  • 1
    @ArdaAytekin yeah, deleting them explicitly is like saying to the compiler that you don't want the type to be moveable, and if you don't delete them then the copy versions will be used instead for this case. – TartanLlama Jan 23 '18 at 13:49