Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing smart-pointers by reference

Tags:

Smart-pointers are generally tiny so passing by value isn't a problem, but is there any problem passing references to them; or rather are there specific cases where this mustn't be done?

I'm writing a wrapper library and several of my classes wrap smart-pointer objects in the underlying library... my classes are not smart-pointers but the APIs currently pass smart-pointer objects by value.

e.g current code:

void class::method(const AnimalPtr pAnimal) { ... } 

becomes

void class::method(const MyAnimal &animal){...} 

where MyAnimal is my new wrapper class encapsulating AnimalPtr.

There is no guarantee the Wrapper classes won't one day grow beyond wrapping a smart-pointer, so passing by value makes me nervous.

like image 393
Mr. Boy Avatar asked Jun 28 '13 15:06

Mr. Boy


People also ask

Should you pass smart pointers by reference?

It's ok to pass a smart pointer by reference, except if it's to a constructor. In a constructor, it's possible to store a reference to the original object, which violates the contract of the smart pointers.

Can pointers be passed by reference?

You would want to pass a pointer by reference if you have a need to modify the pointer rather than the object that the pointer is pointing to. This is similar to why double pointers are used; using a reference to a pointer is slightly safer than using pointers.

How do I return a smart pointer in C++?

So the best way to return a shared_ptr is to simply return by value: shared_ptr<T> Foo() { return shared_ptr<T>(/* acquire something */); }; This is a dead-obvious RVO opportunity for modern C++ compilers.

Is shared_ptr reference counting?

The shared reference counter counts the number of owners. Copying a std::shared_ptr increases the reference count by one. Destroying a std::shared_ptr decreases the reference count by one. If the reference count becomes zero, the resource will automatically be released.


2 Answers

You should pass shared pointers by reference, not value, in most cases. While the size of a std::shared_ptr is small, the cost of copying involves an atomic operation (conceptually an atomic increment and an atomic decrement on destruction of the copy, although I believe that some implementations manage to do a non-atomic increment).

In other cases, for example std::unique_ptr you might prefer to pass by value, as the copy will have to be a move and it clearly documents that ownership of the object is transferred to the function (if you don't want to transfer ownership, then pass a reference to the real object, not the std::unique_ptr).

In other cases your mileage might vary. You need to be aware of what the semantics of copy are for your smart pointer, and whether you need to pay for the cost or not.

like image 154
David Rodríguez - dribeas Avatar answered Sep 25 '22 04:09

David Rodríguez - dribeas


It's ok to pass a smart pointer by reference, except if it's to a constructor. In a constructor, it's possible to store a reference to the original object, which violates the contract of the smart pointers. You would likely get memory corruption if you did that. Even if your constructor does not today store the reference, I would still be wary because code changes and it's an easy thing to miss if you decide later you need to hold the variable longer.

In a normal function, you cannot store a function parameter as a reference anywhere because references must be set during their initialization. You could assign the reference to some longer-living non-reference variable, but that would be a copy and so would increase its lifetime appropriately. So in either case, you could not hold onto it past when the calling function might have freed it. In this case, you might get a small performance boost with a reference, but I wouldn't plan on noticing it in most cases.

So I would say - constructor, always pass by value; other functions, pass by reference if you want.

like image 26
JoshG79 Avatar answered Sep 22 '22 04:09

JoshG79