использовать пользовательский удалитель
Проблема заключается в том, unique_ptr<T>
что деструктор должен вызывать T::~T()
свой собственный деструктор, свой оператор присваивания перемещения и unique_ptr::reset()
функцию-член (только). Однако они должны вызываться (неявно или явно) в нескольких ситуациях PIMPL (уже в деструкторе внешнего класса и операторе присваивания перемещения).
Как уже указывалось в другой ответ, один из способов избежать этого, чтобы переместить все операции, требующие unique_ptr::~unique_ptr()
, unique_ptr::operator=(unique_ptr&&)
иunique_ptr::reset()
в исходный файл , в котором фактически определен класс Pimpl помощник.
Тем не менее, это довольно неудобно и в некоторой степени противоречит самой сути проблемы. Гораздо более чистое решение, позволяющее избежать всего, что заключается в использовании пользовательского средства удаления и только перемещать его определение в исходный файл, где живет класс помощника pimple . Вот простой пример:
// 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; }
Вместо отдельного класса для удаления вы также можете использовать свободную функцию или static
член foo
в сочетании с лямбда-выражением:
class foo {
struct pimpl;
static void delete_pimpl(pimpl*);
std::unique_ptr<pimpl,[](pimpl*ptr){delete_pimpl(ptr);}> m_pimpl;
};