If this is your first visit, be sure to
check out the FAQ by clicking the
link above. You may have to register or Login
before you can post: click the register link above to proceed. To start viewing messages,
select the forum that you want to visit from the selection below.

Re: Passing std:: or boost::shared_ptr as a reference to a function

Originally Posted by Fahrenheit

So the question is - is there any reason I should not do such optimization? Is there any corner case I did not consider?

If you do this you no longer have a perfectly fine smart pointer. It may cause the problems you wanted to avoid by introducing a smart pointer in the first place. You've planted a mine ready to go off. It beats the purpose of using smart pointers.

If you really need this optimization I suggest you instead pass the object the smart pointer points to by const reference, like

Code:

void foo(const type& arg);
//
std::shared_ptr<type> p;
//
foo(*p);

It's assumed that foo is a low-level function/method that has been identified as a performance bottleneck. It should also be inlined.

It's also a good idea to reconsider whether you really need this smart pointer. If it's used very locally in low-level performance sensitive code and the ownership is perfectly clear it may be overkill.

Re: Passing std:: or boost::shared_ptr as a reference to a function

Lindley, sure, I will yet check out which is actually faster with some benchmark. It is really interesting question. Btw, even if they will tie on single-threaded test in multi-threaded reference to shared_ptr will still be the winner due to less interference with other threads.

Nuzzle, what kind of mine you are talking about? I understand what in this case I will get two copies of the object (one up the stack, and one down the stack) for only 1 reference count, but I can't think of any specific scenario that will break under these circumstances (synchronous call to some function)

Re: Passing std:: or boost::shared_ptr as a reference to a function

Originally Posted by Fahrenheit

what kind of mine you are talking about?

I cannot speak for nuzzle, but given that it makes no sense to pass a shared_ptr to a function not supposed to store somewhere a copy ( both in terms of efficiency and semantics ), I wonder in what reasonable scenario a function that acts by propagating ownership of an object to other objects happens to be in performance sensitive code.

For example, consider an high performance algorithm passing back and forth shared pointers to objects between, say, a number of containers; I think you can always refactor the algorithm in such a way to use plain pointers during calcualtions mantaining a central repository of unique or shared smart pointers to be cleaned/mantained strictly before or after the algorithm performance sensitive core. Moreover, I think such a refactoring would be actually cleaner, being more correct from a semantical POV.

Originally Posted by Lindley

If they are, then every dereference within that function will incurr an extra indirection cost.

note that a function taking a const share_ptr& can always immediately make a copy from it, hence avoiding such an issue, especially if the function is inlined. The same flexibility cannot be said for a function taking a shared_ptr directly.

Re: Passing std:: or boost::shared_ptr as a reference to a function

I was thinking more about it, and if the function that gets that const shared_ptr<T>& as argument wants to store it somewhere for future use it is absolutely legal, as the stored copy will get its own reference counted.

Of course if the stored copy is, again, a reference then it won't - but this is a bad design decision to store a reference to some external object - give or take share_ptr

Also - I did more or less realistic benchmark of passing shared_ptr, and following are my conclusions:
1) Passing by reference is about 10 times faster than passing by value
2) Similar cost ratio is for both std::shared_ptr and boost::shared_ptr, but boost's smart pointer is about 15&#37; faster when passed by value
3) It doesn't matter if the object was created with new T(), or with make_shared<T>() - performance numbers are the same

Re: Passing std:: or boost::shared_ptr as a reference to a function

I've changed my mind on this topic. It's perfectly fine to pass a shared_ptr by const reference. In fact it's even best practice.

If the code is sequential or if it's concurrent and properly synchronized it doesn't matter whether you pass by value or by const reference. Both are correct and will work equally fine. So the choise becomes a matter of which is most efficient and it will be const reference.

From a purely conceptual standpoint it still makes sense to treat a shared_ptr exactly like a bald pointer that is passing it by value. But since also a bald pointer would be passed by const reference if that were faster I see no reason why a shared_ptr couldn't be passed by const reference now that this actually is faster. It's the same consideration one makes for any type when deciding how to pass it.

For an excellent clarification of this issue by three top C++ experts see here,

In my view knowing that a shared_ptr can be passed efficiently by const reference without causing any harm to the integrity of a program makes it an even better choise over bald pointers. This is always true in sequential code and it's true in concurrent code as long as the shared_ptr implementation sports an atomic reference counter and the code is also otherwise properly synchronized.

Re: Passing std:: or boost::shared_ptr as a reference to a function

I've changed my mind on this topic. It's perfectly fine to pass a shared_ptr by const reference. In fact it's even best practice.

IMO, if it has a constructor, you pass it by const_reference. Simple as that.

If the function then wants to do something mutable with the object, it's the function's own job to create a copy locally. The function signature shouldn't burden the caller with such petty detail.

That said, passing a shared_ptr by const reference doesn't prevent you from mutating the targeted object anyways, it just prevents you from re-seating it.

BTW, most algorithms will swap their objects (and even move them in C++11). AFAIK, there is no extra cost to do this operation on shared_ptr over a naked one.

Is your question related to IO?
Read this C++ FAQ article at parashift by Marshall Cline. In particular points 1-6.
It will explain how to correctly deal with IO, how to validate input, and why you shouldn't count on "while(!in.eof())". And it always makes for excellent reading.