Rule A8-4-11 (required, design, automated)
A smart pointer shall only be used as a parameter type if it expresses lifetime semantics
Rationale
If the object passed into the function is merely used without affecting the lifetime, it is preferable to pass it by reference or raw pointer instead. Keeping a copy of a std::shared_ptr or moving a std::unique_ptr would be examples that affect the lifetime. Note: When an object whose lifetime is managed by a non-local smart pointer is passed by reference or raw pointer, care needs to be taken that the lifetime of the object doesn’t end during the duration of the called function. In the case of a std::shared_ptr this can be achieved by keeping a local copy of the shared_ptr.
Exception
A non-owning smart pointer, like std::observer_ptr from the C++ Library Fundamentals TS v2, that documents the non-owning property of the parameter does not violate this rule.
Example
// $Id: A8-4-11.cpp 307966 2018-02-16 16:03:46Z christof.meerwald $
#include <cstdint>
#include <memory>
#include <numeric>
#include <vector>
class A
{
public:
void do_stuff();
};
// Non-Compliant: passing object as smart pointer
void foo(std::shared_ptr<A> a)
{
if (a)
{
a->do_stuff();
}
else
{
// ...
}
}
// Compliant: passing as raw pointer instead
void bar(A *a)
{
if (a != nullptr)
{
a->do_stuff();
}
else
{
// ...
}
}
class B
{
public:
void add_a(std::shared_ptr<A> a)
{
m_v.push_back(a);
}
private:
std::vector<std::shared_ptr<A>> m_v;
};
// Compliant: storing the shared pointer (affecting lifetime)
void bar(B &b, std::shared_ptr<A> a)
{
b.add_a(a);
}
See also
C++ Core Guidelines [11]: R.30: Take smart pointers as parameters only to explicitly express lifetime semantics.
C++ Core Guidelines [11]: R.37: Do not pass a pointer or reference obtained from an aliased smart pointer. C++ Core Guidelines [11]: F.7: For general use, take T* or T& arguments rather than smart pointers. A18-5-2 in section 6.18.5