Where is the destructor hiding in this code?

I am having trouble understanding why the move constructor Foo trying to call ~ptr in the following example:

 #include <utility> template <typename T, typename Policy> class ptr { T * m_t; public: ptr() noexcept : m_t(0) {} explicit ptr(T *t) noexcept : m_t(t) {} ptr(const ptr &other) noexcept : m_t(Policy::clone(other.m_t)) {} ptr(ptr &&other) noexcept : m_t(other.m_t) { other.m_t = 0; } ~ptr() noexcept { Policy::delete_(m_t); } ptr &operator=(const ptr &other) noexcept { ptr copy(other); swap(copy); return *this; } ptr &operator=(ptr &&other) noexcept { std::swap(m_t,other.m_t); return *this; } void swap(ptr &other) noexcept { std::swap(m_t, other.m_t); } const T * get() const noexcept { return m_t; } T * get() noexcept { return m_t; } }; class FooPolicy; class FooPrivate; class Foo { // some form of pImpl: typedef ptr<FooPrivate,FooPolicy> DataPtr; DataPtr d; public: // copy semantics: out-of-line Foo(); Foo(const Foo &other); Foo &operator=(const Foo &other); ~Foo(); // move semantics: inlined Foo(Foo &&other) noexcept : d(std::move(other.d)) {} // l.35 ERR: using FooDeleter in ~ptr required from here Foo &operator=(Foo &&other) noexcept { d.swap(other.d); return *this; } }; 

GCC 4.7:

 foo.h: In instantiation of 'ptr<T, Policy>::~ptr() [with T = FooPrivate; Policy = FooPolicy]': foo.h:34:44: required from here foo.h:11:14: error: incomplete type 'FooPolicy' used in nested name specifier 

Clang 3.1-pre:

 foo.h:11:14: error: incomplete type 'FooPolicy' named in nested name specifier ~ptr() { Policy::delete_(m_t); } ^~~~~~~~ foo.h:34:5: note: in instantiation of member function 'ptr<FooPrivate, FooPolicy>::~ptr' requested here Foo(Foo &&other) : d(std::move(other.d)) {} ^ foo.h:23:7: note: forward declaration of 'FooPolicy' class FooPolicy; ^ foo.h:11:20: error: incomplete definition of type 'FooPolicy' ~ptr() { Policy::delete_(m_t); } ~~~~~~^~ 2 errors generated. 

What's happening? I write move constructors not to run copies of ctors and dtors. Please note that this is a header file that tries to hide its implementation (pimpl idiom), therefore making FooDeleter full type is not an option.

EDIT : after Bo's answer, I added noexcept everywhere I could (edited above). But the mistakes are the same.

+6
source share
1 answer

You create a new Foo object containing the ptr<something> element. If the Foo constructor fails, the compiler must invoke destructors for any fully constructed elements of the partially built Foo .

But it cannot create an instance of ~ptr<incomplete_type>() , so it does not work.

You have a similar case with a private destructor. It also prevents you from creating objects of this type (unless it is made from a friend or member function).

+9
source

Source: https://habr.com/ru/post/909202/


All Articles