In this question I asked "pimpl: shared_ptr or unique_ptr" I've been convinced that the proper usage of the pimpl idiom is to use a unique_ptr
, not a shared_ptr
. It should act to the user as if there is no pointer at all, whereas quite clearly the shared_ptr
introduces aliasing upon copying, which definitely acts like a pointer.
So, lets say a user wants to create a shared_ptr
to my pimpl object (say if they want actually want multiple aliases to it). For example:
shared_ptr<my_pimpl> p(new my_pimpl());
That would result in a shared_ptr
pointing to a unique_ptr
pointing to my implementation.
It would be nice if I could achieve something like the following:
my_pimpl x; // (1)
shared_ptr<my_pimpl> p(new my_pimpl()); // (2) Pointer to pointer here.
x.f(); // (3)
p->f(); // (4)
but with somehow getting rid of the pointer to pointer, whilst still maintaining the implementation hiding of pimpl.
Any ideas how to achieve this (I'm happy to change the line (2) and obviously my_pimpl
, but want lines (3) and (4) to stay the same).
There are a number of possible approaches depending on your constraints.
Create a class shared_my_pimpl
which has the same interface as my_pimpl
but internally uses a shared_ptr instead of a unique_ptr
. Now create a class shared_ptr_my_pimpl
which holds a shared_my_pimpl
and has an operator->
which returns a pointer to the shared_my_pimpl
, so that you get ->
notation instead of .
notation for member access. You can add a function make_shared_ptr_my_pimpl
to make it look more like shared_ptr
usage.
Disadvantages:
shared_ptr<x>
but shared_ptr_my_pimpl
; it's just pretending to be a shared_ptr
.my_pimpl*
or my_pimpl&
to the object; it's a different type which just behaves the same.Create an interface my_pimpl_interface
with all relevant functions pure virtual. Derive both my_pimpl
and my_pimpl::impl
(your pimpl implementation class) from this interface. Add a function make_shared_my_pimpl
which returns a shared_ptr<my_pimpl_interface>
to a my_pimpl::impl
. You can now refer to both the plain object and the shared_ptr object as my_pimpl_interface&
.
Disadvantages:
my_pimpl
object will also pay this overhead.