For general use, take `T*` or `T&` arguments rather than smart pointers
Reason
Passing a smart pointer transfers or shares ownership and should only be used when ownership semantics are intended. A function that does not manipulate lifetime should take raw pointers or references instead.
Passing by smart pointer restricts the use of a function to callers that use smart pointers. A function that needs a widget should be able to accept any widget object, not just ones whose lifetimes are managed by a particular kind of smart pointer.
Passing a shared smart pointer (e.g., std::shared_ptr) implies a run-time cost.
Example
// accepts any int*
void f(int*);
// can only accept ints for which you want to transfer ownership
void g(unique_ptr<int>);
// can only accept ints for which you are willing to share ownership
void g(shared_ptr<int>);
// doesn't change ownership, but requires a particular ownership of the caller
void h(const unique_ptr<int>&);
// accepts any int
void h(int&);
Example, bad
// callee
void f(shared_ptr<widget>& w)
{
// ...
use(*w); // only use of w -- the lifetime is not used at all
// ...
};
// caller
shared_ptr<widget> my_widget = /* ... */;
f(my_widget);
widget stack_widget;
f(stack_widget); // error
Example, good
// callee
void f(widget& w)
{
// ...
use(w);
// ...
};
// caller
shared_ptr<widget> my_widget = /* ... */;
f(*my_widget);
widget stack_widget;
f(stack_widget); // ok -- now this works
Note
We can catch many common cases of dangling pointers statically (see lifetime safety profile). Function arguments naturally live for the lifetime of the function call, and so have fewer lifetime problems.
Enforcement
Suggest using a T* or T& instead.
Suggest using a T* or T& instead.
- (Simple) Warn if a function takes a parameter of a smart pointer type (that overloads
operator->oroperator*) that is copyable but the function only calls any of:operator*,operator->orget(). - Flag a parameter of a smart pointer type (a type that overloads
operator->oroperator*) that is copyable/movable but never copied/moved from in the function body, and that is never modified, and that is not passed along to another function that could do so. That means the ownership semantics are not used.
See also: