Verwenden Sie einen benutzerdefinierten Löscher
Das Problem ist, dass unique_ptr<T>
der Destruktor T::~T()
in seinem eigenen Destruktor, seinem Verschiebungszuweisungsoperator und seiner unique_ptr::reset()
Elementfunktion (nur) aufgerufen werden muss . Diese müssen jedoch in mehreren PIMPL-Situationen (implizit oder explizit) aufgerufen werden (bereits im Destruktor und Verschiebungszuweisungsoperator der äußeren Klasse).
Wie bereits in einer anderen Antwort darauf hingewiesen, ein Weg , dies zu vermeiden , sich zu bewegen , alle Operationen , die erfordern unique_ptr::~unique_ptr()
, unique_ptr::operator=(unique_ptr&&)
und unique_ptr::reset()
in die Quelldatei , in der die Pimpl Helfer Klasse tatsächlich definiert.
Dies ist jedoch ziemlich unpraktisch und widerspricht bis zu einem gewissen Grad dem eigentlichen Punkt des Pickel-Idoims. Eine viel sauberere Lösung, die alles vermeidet, einen benutzerdefinierten Löscher zu verwenden und seine Definition nur in die Quelldatei zu verschieben, in der sich die Pickel-Hilfsklasse befindet. Hier ist ein einfaches Beispiel:
// 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; }
Anstelle einer separaten Deleter-Klasse können Sie auch eine freie Funktion oder ein static
Mitglied von foo
in Verbindung mit einem Lambda verwenden:
class foo {
struct pimpl;
static void delete_pimpl(pimpl*);
std::unique_ptr<pimpl,[](pimpl*ptr){delete_pimpl(ptr);}> m_pimpl;
};