passing shared_ptr<> by_value or by-reference?

Hi! Don't know, if this is a FAQ, but I couldn't find an answer to this question: Is there a common sense about how a shared_ptr<> should be passed to functions/methods: by-value or by-(const-)reference? 1) void test(boost::shared_ptr<A> a); 2) void test(boost::shared_ptr<A>& const a);

Kosta wrote:
Hi!
Don't know, if this is a FAQ, but I couldn't find an answer to this question:
Is there a common sense about how a shared_ptr<> should be passed to functions/methods: by-value or by-(const-)reference?
1) void test(boost::shared_ptr<A> a); 2) void test(boost::shared_ptr<A>& const a);
You should pass by value. Passing a shared_ptr means giving the opportunity to the callee to use the data without worrying about its lifetime. Would you pass it by ref, the callee won't own the the pointee and hence cannot use it reliabily (it may get deleted behind its back). By passing it by value, the callee makes a copy of the shared_ptr, hence incrementing the ref count. The pointer won't get deleted while the callee use the pointer. Hope it makes sense.

Is there a common sense about how a shared_ptr<> should be passed to functions/methods: by-value or by-(const-)reference?
1) void test(boost::shared_ptr<A> a); 2) void test(boost::shared_ptr<A>& const a);
You should pass by value. Passing a shared_ptr means giving the opportunity to the callee to use the data without worrying about its lifetime. Would you pass it by ref, the callee won't own the the pointee and hence cannot use it reliabily (it may get deleted behind its back). By passing it by value, the callee makes a copy of the shared_ptr, hence incrementing the ref count. The pointer won't get deleted while the callee use the pointer. Hope it makes sense.
I'm not 100% sure that such a scenario (the pointer gets deleted behind its back if the shared_ptr is passed by ref) is technically possible, but I agree that logically it's better to pass by value. And I would like to add another thing. You should consider what are the requirements of the function. If it wants to be one of the shared owners of the pointer, then it should get a shared_ptr by value. On the other hand, if the function doesn't care about ownership, and only needs an object, then it should get a simple pointer ot reference (either const or not) to the object, like a "regular" function. Elaboration: When we look at a "regular" function 'void f([const] T &)', it looks obvious to us that f() requires the caller to supply a T object, and guarantee that it stays alive during the execution of f(). So if this is what you want, use this semantics and not shared_ptr. Hope my opinion was useful to anyone.

Yuval Ronen wrote:
Is there a common sense about how a shared_ptr<> should be passed to functions/methods: by-value or by-(const-)reference?
1) void test(boost::shared_ptr<A> a); 2) void test(boost::shared_ptr<A>& const a);
You should pass by value. Passing a shared_ptr means giving the opportunity to the callee to use the data without worrying about its lifetime. Would you pass it by ref, the callee won't own the the pointee and hence cannot use it reliabily (it may get deleted behind its back). By passing it by value, the callee makes a copy of the shared_ptr, hence incrementing the ref count. The pointer won't get deleted while the callee use the pointer. Hope it makes sense.
I'm not 100% sure that such a scenario (the pointer gets deleted behind its back if the shared_ptr is passed by ref) is technically possible, but I agree that logically it's better to pass by value.
It is possible. In a multithreaded program, another thread may reset() a. In a single-threaded program, a function called by test() may reset a. I have encountered it myself. If these cases are not a concern, pass by const ref is usually slightly more efficient.

Peter Dimov wrote:
Is there a common sense about how a shared_ptr<> should be passed to functions/methods: by-value or by-(const-)reference?
1) void test(boost::shared_ptr<A> a); 2) void test(boost::shared_ptr<A>& const a);
You should pass by value. Passing a shared_ptr means giving the opportunity to the callee to use the data without worrying about its lifetime. Would you pass it by ref, the callee won't own the the pointee and hence cannot use it reliabily (it may get deleted behind its back). By passing it by value, the callee makes a copy of the shared_ptr, hence incrementing the ref count. The pointer won't get deleted while the callee use the pointer. Hope it makes sense.
I'm not 100% sure that such a scenario (the pointer gets deleted behind its back if the shared_ptr is passed by ref) is technically possible, but I agree that logically it's better to pass by value.
It is possible. In a multithreaded program, another thread may reset() a. In a single-threaded program, a function called by test() may reset a. I have encountered it myself.
But doesn't that violate the thread-safety guarantee of the shared_ptr interface anyway? Using two different shared pointers to the same object is guaranteed to be thread safe, but you aren't supposed to let a thread modify a particular shared pointer instance while another thread is accessing it. The fact that it is passed by const reference in a function call is a red herring, since the multiple access violation can occur before or after the call too. -- Jon Biggar Levanta jon@levanta.com

It is possible. In a multithreaded program, another thread may reset() a. In a single-threaded program, a function called by test() may reset a. I have encountered it myself.
But doesn't that violate the thread-safety guarantee of the shared_ptr interface anyway? Using two different shared pointers to the same object is guaranteed to be thread safe, but you aren't supposed to let a thread modify a particular shared pointer instance while another thread is accessing it.
The fact that it is passed by const reference in a function call is a red herring, since the multiple access violation can occur before or after the call too.
I think multithreading is red herring. It just a problem with passing by reference (and multithreading just adds to the possibility of this to happend): shared_ptr<A> a; void load() { a = new A; } void unload() { a.reset(); } void foo() { unload(); } void process( shared_ptr<A> const& a ) { .... // here a is valid foo(); // this function may as well be called from other thread .... // here a is invalid } int main() { load(); process( a ); unload(); } Gennadiy

I think multithreading is red herring. It just a problem with passing by reference (and multithreading just adds to the possibility of this to happend):
shared_ptr<A> a;
void load() { a = new A; } void unload() { a.reset(); }
void foo() { unload(); }
void process( shared_ptr<A> const& a ) { .... // here a is valid foo(); // this function may as well be called from other thread .... // here a is invalid }
int main() { load(); process( a ); unload(); }
I don't understand where the multithreading is in this program, however it should not pose a problem when passing to a function as a reference. In this case, the callstack looks like foo() process() main() <-- a's handle is held here Theres no need to keep the shared_ptr as a value except when you need to store it post-function call. eg: struct whatever { shared_ptr<X> storage; <-- must be value whatever( shared_ptr<X>& x ) : storage(x) {} <-- ok to pass by ref void do_stuff() { storage->exec(); } <-- if not stored as value, might be hanging ref }; void main() { shared_ptr<X> thenew = make_new(); whatever stuff(thenew); <-- ptr remains valid until call returns thenew.reset(); <-- if not stored as value then storage now invalid stuff.do_stuff(); <-- call and use stored ptr. } so, store shared_ptrs as value, pass as reference/const-ref. Paul
participants (7)
-
Amerio
-
Gennadiy Rozental
-
Jonathan Biggar
-
Kosta
-
Paul
-
Peter Dimov
-
Yuval Ronen