almost always std::shared_ptr NOT!

given the following example classes:

struct Base
{
  virtual Base() = default;
};

struct D : Base
{
};

In good old legacy-code you had a function signature like this:

void func(const Base& base);

In the modern times with shared_ptr it will be this !?

void func(const std::shared_ptr<const Base>& ptr);

But:

int main()
{
  auto ptr = std::make_shared<D>();

  func(ptr);
}

in line 5 (the func-function call) the ptr of type std::shared_ptr<D> has to be converted into a const std::shared_ptr<const Base>&.

So the compiler creates a temporary std::shared_ptr<const Base> object which binds to the const std::shared_ptr<const Base>&.

But creating the temporary involves reference counting, incrementing before entering the function and decrementing when it returns.

If in good old legacy-code the func only operated and never stored the reference (or address of the object), then in modern code it should be a reference too.