Привожу код заготовки реализации идиомы pImpl с этого сайта
// in header file
class widget
{
public:
widget();
~widget();
private:
class impl;
unique_ptr
// in implementation file
class widget::impl
{
// :::
};
widget::widget() : pimpl{ new impl{ /*...*/ } } { }
widget::~widget() { }
Далее там написано следующее:
Prefer to hold the Pimpl using a unique_ptr. It’s more efficient than
using a shared_ptr, and correctly expresses the intent that the Pimpl
object should not be shared.
Вопрос: в чем конкретно эффективность (предпочтительное более быстрое перемещение?) использования std::unique_ptr и почему предлагается не разделять реализацию между несколькими экземплярами? Я ранее задавал вопрос относительно идиомы copy-on-write, почему бы не использовать реализацию идиомы pImpl на указателе типа shared_ptr и дополнить ее вот такими реализациями операторов, характерными для COW идиомы:
// Non-const * and -> , copying
T& operator*()
{
copy();
return *m_sp;
}
T* operator->()
{
copy();
return m_sp.operator->();
}
// Const * and -> methods no need to copy
const T& operator*() const
{
return *m_sp;
}
const T* operator->() const
{
return m_sp.operator->();
}
Ответ
Для начала нужно понимать разницу в идеологии между shared_ptr и unique_ptr. Первый подразумевает, что объект будет в общем владении, а unique_ptr только единоличное владение. Так как pimpl подразумевает единоличное владение (не, можно конечно сделать и расшаренное, но это как то не нормально), то unique_ptr в самый раз.
Почему же оно быстрее? все очень просто. shared_ptr внутри себя содержит как минимум счетчик ссылок либо на атомиках, либо с мютексами. В любом случае это не быстро. unique_ptr это все не нужно. В многих случаях компилятор может оптимизировать до такой степени, что будет не хуже голого указателя.
почему предлагается не разделять реализацию между несколькими экземплярами
потому что это будет уже не pimpl.
дополнить ее вот такими реализациями операторов, характерными для COW идиомы:
Ваша реализация требует наличие некой функции copy. И второе - она не очень thread-safe.
Почему такое не сделали в shared_ptr? Потому что это был бы cow_ptr. Это лишняя функциональность, которая обычно не нужна (если бы она была нужна, то наверно она появилась бы и в бусте, откуда пришел этот умный указатель), а в с++ не принято "платить за то, что не используется".
Комментариев нет:
Отправить комментарий