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?

+3


source to share


1 answer


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 ++.

+6


source







All Articles