usar un eliminador personalizado
El problema es que unique_ptr<T>
debe llamar al destructor T::~T()
en su propio destructor, su operador de asignación de movimiento y la unique_ptr::reset()
función miembro (solo). Sin embargo, estos deben llamarse (implícita o explícitamente) en varias situaciones PIMPL (ya en el destructor de la clase externa y el operador de asignación de movimiento).
Como ya se ha señalado en otra respuesta, una forma de evitar que se va a mover todas las operaciones que requieren unique_ptr::~unique_ptr()
, unique_ptr::operator=(unique_ptr&&)
y unique_ptr::reset()
en el archivo de origen, donde la clase pimpl ayudante se define realmente.
Sin embargo, esto es bastante inconveniente y desafía hasta cierto punto el punto mismo de la idolatría. Una solución mucho más limpia que evita todo eso es usar un eliminador personalizado y solo mover su definición al archivo fuente donde vive la clase de ayuda de espinillas. Aquí hay un ejemplo simple:
// file.h
class foo
{
struct pimpl;
struct pimpl_deleter { void operator()(pimpl*) const; };
std::unique_ptr<pimpl,pimpl_deleter> m_pimpl;
public:
foo(some data);
foo(foo&&) = default; // no need to define this in file.cc
foo&operator=(foo&&) = default; // no need to define this in file.cc
//foo::~foo() auto-generated: no need to define this in file.cc
};
// file.cc
struct foo::pimpl
{
// lots of complicated code
};
void foo::pimpl_deleter::operator()(foo::pimpl*ptr) const { delete ptr; }
En lugar de una clase de eliminación separada, también puede usar una función o static
miembro libre foo
junto con un lambda:
class foo {
struct pimpl;
static void delete_pimpl(pimpl*);
std::unique_ptr<pimpl,[](pimpl*ptr){delete_pimpl(ptr);}> m_pimpl;
};