Привожу код заготовки реализации идиомы pImpl с этого сайта.
// in header file
class widget
{
public:
widget();
~widget();
private:
class impl;
unique_ptr<impl> pimpl;
};
// 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. Это лишняя функциональность, которая обычно не нужна (если бы она была нужна, то наверно она появилась бы и в бусте, откуда пришел этот умный указатель), а в с++ не принято "платить за то, что не используется".
Если вы дополните умный указатель этими операторами - это будет уже не shared_ptr
, а уже какой-нибудь cow_ptr
. И да, так тоже будет работать. Тут главное - найти способ вынести copy()
в модуль реализации, потому что нельзя скопировать необъявленный тип данных.
Как-то так в итоге должно получиться:
class widget
{
public:
widget();
~widget();
private:
class impl;
impl* copy(pimpl* impl);
cow_ptr<impl, &widget::copy> pimpl;
};
Однако, на самом деле операция копирования объекта - очень странная по смыслу. И в большинстве прикладных случаев ее явно запрещают. А если копирование запрещено архитектурно, то зачем все эти сложности с реализацией?
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
Здравствуйте, задача состоит в следующем : Изначально нам дан массив double, который нужно зашифровать xor-ом, я привожу массив double к char массиву...
Для формирования отчетов использую QWebEnginePage, из которого можно производить печать в PDF, все очень удобно, но присутствует проблема с печатью...
Изучаю Opengl 3x в исходном коде урока произошла ошибка gl
задача - составить программу для управления даннымиДанные считываются из файла в структуру, из структуры в вектор(для редактирования и так...