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.
Sure, I can help with you that. I assume you have some understanding of ownership semantics in C++. Is that true?
Good.
Ok, I can only think of two reasons to take a
shared_ptr
argument:shared_ptr
s.Which one are you interested in?
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.Exactly.
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.
The one where you share the ownership? Ok. How do you share ownership with
shared_ptr
?Then the function will need to make a copy of a
shared_ptr
, correct?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.
The function can simply move the
shared_ptr
argument into its storage. Moving ashared_ptr
is cheap because it doesn't change any reference counts.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.The usual rules apply. Smart pointers don't change anything.
Right.
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.
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.