sử dụng một deleter tùy chỉnh
Vấn đề là unique_ptr<T>
phải gọi hàm hủyT::~T()
trong hàm của chính nó, toán tử gán chuyển động của nó vàunique_ptr::reset()
hàm thành viên (chỉ). Tuy nhiên, chúng phải được gọi (ngầm hoặc rõ ràng) trong một số tình huống PIMPL (đã có trong toán tử gán và di chuyển gán của lớp ngoài).
Như đã chỉ ra trong câu trả lời khác, một cách để tránh điều đó là để di chuyển tất cả các hoạt động đòi hỏi unique_ptr::~unique_ptr()
, unique_ptr::operator=(unique_ptr&&)
và unique_ptr::reset()
vào file nguồn nơi lớp pimpl helper là thực sự xác định.
Tuy nhiên, điều này khá bất tiện và bất chấp chính điểm của pimpl idoim ở một mức độ nào đó. Một giải pháp sạch hơn nhiều giúp tránh tất cả những điều đó là sử dụng một deleter tùy chỉnh và chỉ di chuyển định nghĩa của nó vào tệp nguồn nơi lớp người trợ giúp nổi mụn sống. Đây là một ví dụ đơn giản:
// 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; }
Thay vì một lớp deleter riêng biệt, bạn cũng có thể sử dụng một hàm miễn phí hoặc static
thành viên foo
kết hợp với lambda:
class foo {
struct pimpl;
static void delete_pimpl(pimpl*);
std::unique_ptr<pimpl,[](pimpl*ptr){delete_pimpl(ptr);}> m_pimpl;
};