Passing shared pointers as arguments

If I declare an object wrapped in a shared pointer:

std::shared_ptr<myClass> myClassObject(new myClass());

then I wanted to pass it as an argument to a method:

DoSomething(myClassObject);

//the called method
void DoSomething(std::shared_ptr<myClass> arg1)
{
   arg1->someField = 4;
}

Does the above simply increment the shared_pt's reference count and everything is cool? Or does it leave a dangling pointer?

Are you still supposed to do this?:

DoSomething(myClassObject.Get());

void DoSomething(std::shared_ptr<myClass>* arg1)
{
   (*arg1)->someField = 4;
}

I think that the 2nd way may be more efficient because it only has to copy 1 address (as opposed to the whole smart pointer), but the 1st way seems more readable and I do not anticipate pushing performance limits. I just want to make sure there's not something dangerous about it.

Thank you.

I want to pass a shared pointer to a function. Can you help me with that?

Sure, I can help with you that. I assume you have some understanding of ownership semantics in C++. Is that true?

Yeah, I'm reasonably comfortable with the subject.

Good.

Ok, I can only think of two reasons to take a shared_ptr argument:

  1. The function wants to share ownership of the object;
  2. The function does some operation that works specifically on shared_ptrs.

Which one are you interested in?

I'm looking for a general answer, so I'm actually interested in both. I'm curious about what you mean in case #2, though.

Examples of such functions include std::static_pointer_cast, custom comparators, or predicates. For example, if you need to find all unique shared_ptr from a vector, you need such a predicate.

Ah, when the function actually needs to manipulate the smart pointer itself.

Exactly.

In that case, I think we should pass by reference.

Yes. And if it doesn't change the pointer, you want to pass by const reference. There's no need to copy since you don't need to share ownership. That's the other scenario.

Ok, got it. Let's talk about the other scenario.

The one where you share the ownership? Ok. How do you share ownership with shared_ptr?

By copying it.

Then the function will need to make a copy of a shared_ptr, correct?

Obviously. So I pass it by a reference to const and copy to a local variable?

No, that's a pessimization. If it is passed by reference, the function will have no choice but to make the copy manually. If it is passed by value the compiler will pick the best choice between a copy and a move and perform it automatically. So, pass by value.

Good point. I must remember that "Want Speed? Pass by Value." article more often.

Wait, what if the function stores the shared_ptr in a member variable, for example? Won't that make a redundant copy?

The function can simply move the shared_ptr argument into its storage. Moving a shared_ptr is cheap because it doesn't change any reference counts.

Ah, good idea.

But I'm thinking of a third scenario: what if you don't want to manipulate the shared_ptr, nor to share ownership?

In that case, shared_ptr is completely irrelevant to the function. If you want to manipulate the pointee, take a pointee, and let the callers pick what ownership semantics they want.

And should I take the pointee by reference or by value?

The usual rules apply. Smart pointers don't change anything.

Pass by value if I'm going to copy, pass by reference if I want to avoid a copy.

Right.

Hmm. I think you forgot yet another scenario. What if I want to share ownership, but only depending on a certain condition?

Ah, an interesting edge case. I don't expect that to happen often. But when it happens you can either pass by value and ignore the copy if you don't need it, or pass by reference and make the copy if you need it.

I risk one redundant copy in the first option, and lose a potential move in the second. Can't I eat the cake and have it too?

If you're in a situation where that really matters, you can provide two overloads, one taking a const lvalue reference, and another taking an rvalue reference. One copies, the other moves. A perfect-forwarding function template is another option.

I think that covers all the possible scenarios. Thank you very much.

Passing shared pointers as arguments, I want to pass a shared pointer to a function. Can you help me with that? Sure, I can help with you that. I assume you have some understanding� General guidelines to follow for passing shared_ptr and unique_ptr as function arguments and at the time of return. You should always assess if passing smart pointers as a function parameter is

I think people are unnecessarily scared of using raw pointers as function parameters. If the function is not going to store the pointer or otherwise affect its lifetime, a raw pointer works just as well and represents the lowest common denominator. Consider for example how you would pass a unique_ptr into a function that takes a shared_ptr as a parameter, either by value or by const reference?

void DoSomething(myClass * p);

DoSomething(myClass_shared_ptr.get());
DoSomething(myClass_unique_ptr.get());

A raw pointer as a function parameter does not prevent you from using smart pointers in the calling code, where it really matters.

How to: Create and use shared_ptr instances, General guidelines to follow for passing shared_ptr and unique_ptr as function arguments and at the time of return. You should always assess� #include <iostream> using namespace std; // function declaration: double getAverage(int *arr, int size); int main { // an int array with 5 elements. int balance[5] = {1000, 2, 3, 17, 50}; double avg; // pass pointer to the array as an argument.

Yes, the entire idea about a shared_ptr<> is that multiple instances can hold the same raw pointer and the underlying memory will only be freed when there the last instance of shared_ptr<> is destroyed.

I would avoid a pointer to a shared_ptr<> as that defeats the purpose as you are now dealing with raw_pointers again.

Passing smart pointers shared_ptr and unique_ptr, In this article I will show you how to pass and return smart pointers to/from Sutter's Mill - GotW #91 Solution: Smart Pointer Parameters. globShared (1) is a globally shared pointer. The function shared takes it argument per reference (2). Therefore, the reference counter of shaPtr will no be increased and the function share will no extend the lifetime of Widget(2011). The issue begins with (3).

Passing-by-value in your first example is safe but there is a better idiom. Pass by const reference when possible - I would say yes even when dealing with smart pointers. Your second example is not exactly broken but it's very !???. Silly, not accomplishing anything and defeats part of the point of smart pointers, and going to leave you in a buggy world of pain when you try to dereference and modify things.

Move smart pointers in and out functions in modern C++, Passing a shared smart pointer (e.g., std::shared_ptr) implies a run-time cost. In other words, if the function just dereferences a pointer to get to the� F.7: For general use, take T* or T& arguments rather than smart pointers Reason Passing a smart pointer transfers or shares ownership and should only be used when ownership semantics are intended (see R.30). Passing by smart pointer restricts the use of a function to callers that use smart pointers.

in your function DoSomething you are changing a data member of an instance of class myClass so what you are modifying is the managed (raw pointer) object not the (shared_ptr) object. Which means at the return point of this function all shared pointers to the managed raw pointer will see their data member: myClass::someField changed to a different value.

in this case, you are passing an object to a function with the guarantee that you are not modifying it (talking about shared_ptr not the owned object).

The idiom to express this is through: a const ref, like so

void DoSomething(const std::shared_ptr<myClass>& arg)

Likewise you are assuring the user of your function, that you are not adding another owner to the list of owners of the raw pointer. However, you kept the possibility to modify the underlying object pointed to by the raw pointer.

CAVEAT: Which means, if by some means someone calls shared_ptr::reset before you call your function, and at that moment it is the last shared_ptr owning the raw_ptr, then your object will be destroyed, and your function will manipulate a dangling Pointer to destroyed object. VERY DANGEROUS!!!

Smart Pointers in Function Arguments, In this post I will try to cover the various ways in which resources can be allocated , owned, and passed around. Stack Objects and Passing� C++ provides a shorthand for passing arguments by address — a shorthand that enables you to avoid having to hassle with pointers. The following declaration creates a variable n1 and a second reference to the same n1 but with a new name, nRef:

Arguments and Smart Pointers — Blog, A shared_ptr stores strong and weak reference counts (see GotW #89). When you pass by value, you have to copy the argument (usually) on� In this example, we are passing a pointer to a function. When we pass a pointer as an argument instead of a variable then the address of the variable is passed instead of the value. So any change made by the function using the pointer is permanently made at the address of passed variable. This technique is known as call by reference in C.

GotW #91 Solution: Smart Pointer Parameters – Sutter's Mill, An std::unique_ptr is a smart pointer that exclusively owns and manages an object (or an array of objects) through a pointer. The exclusive� You can pass a shared_ptr to another function in the following ways: Pass the shared_ptr by value. This invokes the copy constructor, increments the reference count, and makes the callee an owner. There's a small amount of overhead in this operation, which may be significant depending on how many shared_ptr objects you're passing. Use this option when the implied or explicit code contract between the caller and callee requires that the callee be an owner.

C++, 91 votes, 26 comments. Hi All, I have compiled a guideline diagram and article on how to pass shared_ptr and unique_ptr in function arguments and … (f) Passing shared_ptr& is useful for in/out shared_ptr manipulation. void f( shared_ptr<widget>& ); (f) Similarly to (d), this should mainly be used to accept an in/out shared_ptr , when the function is supposed to actually modify the shared_ptr itself.

Comments
  • const std::shared_ptr<myClass>& arg1
  • The second way is broken, the first is idiomatic if you actually need your function to share ownership. But, does DoSomething really need to share ownership? It looks like it should just take a reference instead...
  • @SteveH : It doesn't, but why should your function force special object ownership semantics on its callers if it doesn't actually need them? Your function does nothing that wouldn't be better as void DoSomething(myClass& arg1).
  • @SteveH : The entire purpose of smart pointers is to handle out of the ordinary object ownership issues -- if you don't have those, you shouldn't be using smart pointers in the first place. ;-] As to shared_ptr<> specifically, you must pass by value in order to actually share ownership.
  • Unrelated: in general, std::make_shared is not only more efficient, but also safer than the std::shared_ptr constructor.
  • @Jon: What for? This is all about should I do A or should I do B. I think we all know how to pass objects by value/reference, no?
  • Because prose like "Does that mean I'll pass it by a reference to const to make the copy? No, that's a pessimization" is confusing to a beginner. Passing by a reference to const does not make a copy.
  • @Martinho I disagree with the rule "If you want to manipulate the pointee, take a pointee,". As stated in this answer not taking temporary ownership of an object can be dangerous. In my opinion the default should be to pass a copy for temporary ownership to guarantee object validity for the duration of the function call.
  • @radman No scenario in the answer you link to applies that rule, so it's completely irrelevant. Please write me a SSCCE where you pass by reference from a shared_ptr<T> ptr; (i.e. void f(T&), called with f(*ptr)) and the object does not outlives the call. Alternatively write one where you pass by value void f(T) and trouble strikes.
  • @Martinho check out my example code for the simple self contained correct example. The example is for void f(T&) and involves threads. I think my issue is that the tone of your answer discourages passing ownership of shared_ptr's, which is the safest, most intuitive and least complicated way of using them. I would be extremely against ever advising a beginner to extract a reference to data owned by a shared_ptr<> the possibilities for misuse are great and the benefit is minimal.