I would suggest to pass them by const std::shared_ptr<T>&
. This has two benefits:
- No overhead incurred with reference counts (the reference count is not increased by default)
- The function is free to take a copy of the shared pointer if necessary
I use this a lot in situations where they may (or may not) be a thread handoff. For instance:
struct Foo { void bar() {} };
class BaseImpl
{
public:
void CallBar(const std::shared_ptr<Foo>& f);
{
do_call_bar(f);
}
private:
virtual void do_call_bar(const std::shared_ptr<Foo>& f) = 0;
};
class DerivedDirectCall : public BaseImpl
{
virtual void do_call_bar(const std::shared_ptr<Foo>& f) override
{
f->bar();
}
};
class DerivedAsyncCall : public BaseImpl
{
virtual void do_call_bar(const std::shared_ptr<Foo>& f) override
{
// assume invoke passes this off
// to be done asynchronously
invoke([f] () { f->bar(); });
}
};
Depending on whether the implementation is DerivedDirectCall
or DerivedAsyncCall
the shared pointer will only be copied if necessary.
Also, a comment above linked this article on smart pointers. I want to be clear in that my answer is specifically about passing the smart pointer itself. If you know the lifetime won't necessarily be extended, it's better to pass the pointed to object by reference (or raw pointer, but only it's necessary to allow for nullptr
parameters).