Std :: unique_ptr and std :: shared_ptr as parameters for virtual functions
I am designing a method-based C ++ class interface virtual
to be able to provide extensibility points.
A lot of these public methods require a heap
dedicated object as parameters.
Since I am using modern C ++ templates, I plan on using std::unique_ptr
or std::shared_ptr
for this, but I have doubts about both of them.
Using std :: unique_ptr looks something like this:
class IFoo {
virtual void doSomethingWithUser(std::unique_ptr<User> user) = 0;
}
Forcing the caller to std::unique_ptr
have downsides:
- the caller cannot perform any operations with the provided user as it needs to be moved.
- if any implementation
doSomethingWithUser
needs to store the user in some container, it cannot be created fromstd::shared_ptr
Using std::shared_ptr
for all public methods might solve the problem, but we have to pay for the extra memory space plus atomic incrementing and decrementing the reference count.
Is there a rule of thumb?
source to share
If doSomethingWithUser
ownership is not required, you should not transfer it to this method.
Indeed, copying a shared pointer or moving a unique pointer effectively transfers ownership of the resource.
The parameters for your functions should reflect your intentions regarding the intended ownership of the transferred resources.
If you only need to observe the value and possibly mutate it, you must pass a descriptor without rights to your function.
If you need to keep the resource alive and possibly delete it, then you must pass the ownership descriptor, whether or not it has unique ownership.
In your case, the function name tells me you need to "do something with the user" without forcing it to pass the caller's lifetime. Therefore, you must pass in a non-owning descriptor. This descriptor can be User*
either User&
, and even std::reference_wrapper<User>
or boost::optional<User&>
, depending on your needs.
Your interface should really express what an object is supposed to do and really provide what parameters each function should do, but your interface should also express what ownership it has over its parameters.
I usually prefer references as they ensure that it cannot be null and work well with an object in automatic storage. Some might argue that they prefer raw pointers as a non-nullable descriptor without ownership, but I strongly disagree with that because they force the syntax &object
and allow null.
There is nothing wrong with not owning the original pointers. However, raw ownership pointers should not be used in modern C ++.
source to share