użyj niestandardowego narzędzia do usuwania
Problem polega na tym, że unique_ptr<T>
musi on wywoływać destruktor T::~T()
we własnym destruktorze, jego operatorze przypisania ruchu i unique_ptr::reset()
funkcji elementu (tylko). Jednak muszą być wywoływane (niejawnie lub jawnie) w kilku sytuacjach PIMPL (już w zewnętrznym instrumencie niszczącym klasy i operatorze przypisania ruchu).
Jak już wskazano w innej odpowiedzi, jeden sposób, aby uniknąć sytuacji jest przeniesienie wszystkich operacji, które wymagają unique_ptr::~unique_ptr()
, unique_ptr::operator=(unique_ptr&&)
i unique_ptr::reset()
do pliku źródłowego, gdzie klasa pimpl pomocnik jest właściwie zdefiniowane.
Jest to jednak dość niewygodne i do pewnego stopnia przeczy samemu sensowi idiomu pimpl. Znacznie bardziej przejrzyste rozwiązanie, które pozwala uniknąć korzystania z niestandardowego narzędzia do usuwania i przenosi jego definicję do pliku źródłowego, w którym mieszka klasa pomocnika pryszcza . Oto prosty przykład:
// 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; }
Zamiast oddzielnej klasy deletera możesz także użyć funkcji swobodnej lub static
elementu foo
w połączeniu z lambda:
class foo {
struct pimpl;
static void delete_pimpl(pimpl*);
std::unique_ptr<pimpl,[](pimpl*ptr){delete_pimpl(ptr);}> m_pimpl;
};