3

Since using shared pointers, I frequently run in the situation that I want to pass them to functions which do not (have to) own the object. Because I know that the object is valid during the function call I have four options of passing the pointer:

  1. by value
  2. by reference
  3. weak pointer
  4. raw pointer

At first I started to use weak pointers a lot (because I already had them), but the overhead of locking them all the time is annoying and hits performance. Now I think about either passing raw pointers or shared pointers by reference. Is there a best practice?

Martin R.
  • 1,046
  • 13
  • 14
  • possible duplicate of http://stackoverflow.com/questions/106508/what-is-a-smart-pointer-and-when-should-i-use-one – Captain Obvlious Jul 01 '15 at 20:35
  • 2
    See question 3 on [http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/](http://herbsutter.com/2013/06/05/gotw-91-solution-smart-pointer-parameters/) – Brian Walker Jul 01 '15 at 20:52
  • @Jeff How would you get a `unique_ptr` from a `shared_ptr`? – Alan Stokes Jul 01 '15 at 20:54
  • @Jeff I agree. But you still can't pass a `shared_ptr` to a function expecting a `unique_ptr`, so it doesn't solve the problem of how to pass a `shared_ptr` to a function. – Alan Stokes Jul 01 '15 at 21:14
  • @Jeff: I don't think smart pointers lose their purpose when extracting the bare pointer, since the object is still managed. Especially when a function does not care about ownership at all. – Martin R. Jul 01 '15 at 21:28
  • @Jeff: Sample use case for extracting the bare pointer: you are managing the lifetime of a char array, but you are passing the pointer into a function whose only purpose in life is to fill a char array with data. –  Jul 01 '15 at 22:31
  • @Jeff: It's an excellent candidate if its lifetime needs to be shared between multiple owners, just like anything else. And I'm sure you can imagine other use cases of functions that do things without participating in ownership of objects, if you really wanted to. (although, as my answer indicates, you be passing the objects around when appropriate) –  Jul 01 '15 at 22:48

3 Answers3

6

I would suggest to pass them by const std::shared_ptr<T>&. This has two benefits:

  1. No overhead incurred with reference counts (the reference count is not increased by default)
  2. 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).

Chad
  • 17,081
  • 2
  • 40
  • 60
4

Since using shared pointers, I frequently run in the situation that I want to pass them to functions which do not (have to) own the object.

Your wording makes it sound like what your function actually cares about is the object being pointed to, not the pointer. Thus, you should pass the object (by reference):

void my_func(int &x);

int main()
{
    shared_ptr<int> demo_ptr = make_shared<int>(5);
    my_func(*demo_ptr);
}
3

The lifetime is guaranteed by the stack. If you were to pass a weak_ptr, then the function would just have to acquire a shared_ptr anyway.

You want to either pass the raw pointer by value, or the actual object by reference.

The choice between these two options depends on the semantics of the function you are calling. If nullptr is a valid argument to your function, then pass the raw pointer. Otherwise, pass the object by reference.

paddy
  • 52,396
  • 6
  • 51
  • 93