The types that you use in your interfaces matter a lot. Even if there's documentation, a good API should still be intuitive at a glance. Let's see how different approaches to passing resource parameters to a function can suggest different things to the API consumer.
Consider the following function declarations:
void A(Resource*);
void B(Resource&);
void C(std::unique_ptr<Resource>);
void D(std::unique_ptr<Resource>&);
void E(std::shared_ptr<Resource>);
void F(std::shared_ptr<Resource>&);
When should you use which of those functions?
Since smart pointers are now the standard way to deal with resources, A and B should be left for simple parameter passing and shouldn't be used if you don't do anything with the ownership of the passed objects. A should only be used for a single resource. For example, if you want to pass multiple instances, you could use a container, such as std::span. If you know the...