estoy teniendo problemas para entender por qué el movimiento Foo
constructor intenta invocar ~ptr
en el siguiente ejemplo:¿Dónde se esconde el destructor en este código?
#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.
¿Qué está pasando? Estoy escribiendo constructores de movimientos para evitar ejecutar copiadores y controladores. Tenga en cuenta que este es un archivo de cabecera que intenta ocultar su implementación (idioma pimpl), por lo que FooDeleter
un tipo completo no es una opción.
EDIT: Después de la respuesta de Bo, agregué noexcept
donde pude (editado arriba). Pero los errores siguen siendo los mismos.
mirando ese código por un segundo y tengo un mini dolor de cabeza instantáneo, gracias por la pregunta, tuve un problema similar recientemente afortunadamente no tuvo que seguir – lurscher
No es una respuesta a su pregunta, pero como los mensajes del compilador señalan, ' Deleter (m_t); 'no significa lo que piensas que significa. Define una variable entre paréntesis redundante no utilizada 'm_t' de tipo' Deleter'. – hvd
"Escribo constructores de movimientos para evitar ejecutar copiadores y dtors". Esa no es una buena razón para escribir un constructor de movimientos. Las razones para escribir constructores de movimientos se deben a que se trata de un tipo de contenedor de bajo nivel que necesita semántica de movimiento, o bien está usando Visual Studio que no genera implícitamente constructores de movimiento para usted. De lo contrario, deje que el compilador haga su trabajo. –