0

I have a very basic question about std::shared_ptr. If I have some

std::shared_ptr<A> p;

, where A is some class defined in my code, what is the preferred way to pass this std::shared_ptr as a function argument? Does it make a sense to define my functions that does something with the instance of class A like this:

void func(A &a);

and pass *p to these functions, and then convert 'a' back to std::shared_ptr with shared_from_this() if needed? Is there a reason to do so and what is the common practice? Or I should pass shared_ptr as the argument like this:

void func(std::shared_ptr<A> p); //thread safe
void func(const std::shared_ptr<A> & p); //not thread safe

In the most functions in my project I can use both alternatives, but my colleague said that the first alternative is better because the reference (A&) is always better than a pointer (shared_ptr or A*), because the reference semantics implies that the argument is not null.

Koban
  • 463
  • 1
  • 6
  • 12
  • 1
    Possible duplicate of [Should I pass a shared\_ptr by reference?](https://stackoverflow.com/questions/8385457/should-i-pass-a-shared-ptr-by-reference) – syntagma May 25 '17 at 10:03
  • Not quite a dupe, since that doesn't really address the first option (passing the pointee by reference), but definitely includes some appropriate thinking. – Toby Speight May 25 '17 at 12:48

1 Answers1

1

If you already have a shared pointer, it does not make sense not to pass the shared_ptr, yet create a new one by shared_from_this. That's simply complicated and does not earn you anything.

The usual advice is passing objects by value if the function needs to make a copy anyway (e.g. for storing the object) and passing by const reference if the function only needs to "view" the object.

This also applies to shared pointers.

Hence, e.g.

// Here func in the end needs a copy of the shared_ptr, so pass by value
// the caller can decide whether he wants to move or a copy it in
struct Example {
  shared_ptr<A> m_a;
  void func (shared_ptr<A> a) {
     m_a = move (a);
  }
};

// Here func needs only a reference, so only pass a reference
void func (shared_ptr<A> const & a) {
   a->callme ();
}

// If func needs to see only an object of type A, i.e. does not
// need a pointer, it makes
// more sense to pass an A & or A const &
void func (A const & a) {
   a.callme ();
}

I cannot imagine a situation where passing a shared_ptr by reference would imply problems with thread safety that could be avoided by passing by value. Of course, you should avoid holding a reference to a shared pointer in a thread that does not hold a copy of the shared pointer anywhere. Yet as soon as the thread has a copy of the shared pointer, you can pass references to that shared pointer freely within this thread.

JohnB
  • 13,315
  • 4
  • 38
  • 65