CppCoreGuidlines R.33 Why pass `unique_ptr` by reference? - c++

The CppCoreGuidlines rule R.33 suggests to
Take a unique_ptr<widget>& parameter to express that a function
reseats the widget.
Reason Using unique_ptr in this way both documents and enforces the
function call’s reseating semantics.
Note “reseat” means “making a pointer or a smart pointer refer to a
different object.”
I don't understand why we should pass by reference when reseat means "making a pointer or a smart pointer refer to a different object.”
When the function's purpose is to reseat/change the underlying object the pointer is pointing to, aren't we stealing the ownership from the caller this way and therefore should pass the unique_ptr by value, hence moving it and transferring ownership?
Is there an example that explains why passing a unique_ptr by reference is recommended?

When the function's purpose is to reseat/change the underlying object the pointer is pointing to, aren't we stealing the ownership from the caller this way
No. Neither when we "reseat" a pointer, nor when we change the pointed object, do we take ownership of the pointer i.e. we aren't transferring the ownership.
Is there an example that explains why passing a unique_ptr by reference is recommended?
Here is an example of a function that "reseats" a unique pointer:
void reseat(std::unique_ptr<widget>& ptr) {
ptr = std::make_unique<widget>();
}
If you tried to use a reference to const, then that wouldn't compile at all. If you tried to use a non-reference parameter, then the argument pointer wouldn't be modified and thus the behaviour wouldn't be as desired. The caller would be forced to move their pointer leaving it always null.
You could modify the example to use a pointer to unique pointer, but references are recommended because it isn't possible to pass null by mistake. A reference wrapper would also work, but it would be unnecessarily complicated.
In case we make it point somewhere else, what happens to the object it pointed before?
If a unique pointer points to something other than null, then making it point elsewhere will cause the previously pointed object to be deleted.
Aren't we leaking memory in this case?
No.
Note that the example is simple in order to be easy to understand. Typically I wouldn't recommend to write such function and instead considering to write a function that returns the new unique pointer, and let the caller "reseat" the pointer themselves. But that depends on details.

Related

Is this post correct about "passing shared_ptr in reference"?

Someone made question "should I pass shared_ptr by reference" and he got this reply which has plenty upvotes. https://stackoverflow.com/a/8385731/5543597
It makes me wonder why he has so many upvotes, and if it's true what he is saying:
That depends on what you want. Should the callee share ownership of
the object? Then it needs its own copy of the shared_ptr. So pass it
by value.
If a function simply needs to access an object owned by the caller, go
ahead and pass by (const) reference, to avoid the overhead of copying
the shared_ptr.
The best practice in C++ is always to have clearly defined ownership
semantics for your objects. There is no universal "always do this" to
replace actual thought.
If you always pass shared pointers by value, it gets costly (because
they're a lot more expensive to copy than a raw pointer). If you never
do it, then there's no point in using a shared pointer in the first
place.
Copy the shared pointer when a new function or object needs to share
ownership of the pointee.
Especially here:
Should the callee share ownership of the object? Then it needs its own
copy of the shared_ptr. So pass it by value.
Why creating copy of shared_ptr by passing by value, when it could be reference and callee could just make copy of shared_ptr using reference he received, once he decide to store it in his data?
Or this:
If you never do it, then there's no point in using a shared pointer in
the first place.
When passing it by refence to functions, it still exists in parent function. And once decided to store it, it can be stored without problems.
Are these statements correct?
Yes that answer is correct.
Why creating copy of shared_ptr by passing by value, when it could be reference and callee could just make copy of shared_ptr using reference he received, once he decide to store it in his data?
You could do that. But passing by value serves as self-documentation that the callee might will make a copy. Also, passing by value has the advantage that the function can be called with an rvalue and moved out of, e.g. func( make_shared<T>() );

Is There a Pointer Version of ref that Supports Rvalues?

This is really two questions about ref rolled into one:
Can I use ref on an rvalue? Obviously as the programmer I would have the responsibility to ensure it outlived any calling code.
Is there a pointer version of ref?
The goal of these two sketchy questions are realized in this sketchy answer: https://stackoverflow.com/a/29031944/2642059 Where I'd rather just create a pointer to the vector::data rvalue than create a temp variable.
No, the interface prevents that, as the reference you link to shows. There's an overload taking an lvalue reference; the one taking an rvalue reference is deleted. It's hard to imagine how you might be able to take responsibility for the object's lifetime without being able to access it via an lvalue.
That would be a pointer. The purpose of reference_wrapper is to allow references to be passed around like values (which regular references can't be), while preserving the syntax of a reference (which you'd lose by using a pointer instead). If you want to pass a pointer by value, and have it act like a pointer, then just use a pointer.
I'd rather just create a pointer to the vector::data rvalue than create a temp variable.
That would be a pointer to a temporary. The temporary will be destroyed, invalidating the pointer, before you can do anything with it. As you say, you need to take responsibility for its lifetime, which you do by creating a variable. Once you have that, you have an lvalue.

How do I pass smart pointers into functions?

When passing objects into functions, do the same rules apply to smart pointers as to other objects that contain dynamic memory?
When I pass, for example, a std::vector<std::string> into a function I always consider the following options:
I'm going to change the state of the vector object, but I do not want those changes reflected after the function has finished, AKA make a copy.
void function(std::vector<std::string> vec);
I'm going to change the state of the vector object, and I do want those changes reflected after the function has finished, AKA make a reference.
void function(std::vector<std::string> & vec);
This object is pretty big, so I'd better pass a reference, but tell the compiler not to let me change it.
void function(std::vector<std::string> const& vec);
Now is this the same logic with smart pointers? And when should I consider move semantics? Some guidelines on how I should pass smart pointers is what I desire most.
Smart pointers have pointer semantics, not value semantics (well, not the way you mean it). Think of shared_ptr<T> as a T*; treat it as such (well, except for the reference counting and automatic deletion). Copying a smart pointer does not copy the object it points to, just like copying a T* does not copy the T it points to.
You can't copy a unique_ptr at all. The whole point of the class is that it cannot be copied; if it could, then it wouldn't be a unique (ie: singular) pointer to an object. You have to either pass it by some form of reference or by moving it.
Smart pointers are all about ownership of what they point to. Who owns this memory and who will be responsible for deleting it. unique_ptr represents unique ownership: exactly one piece of code owns this memory. You can transfer ownership (via move), but in so doing, you lose ownership of the memory. shared_ptr represents shared ownership.
In all cases, the use of a smart pointer in a parameter list represents transferring ownership. Therefore, if a function takes a smart pointer, then it is going to claim ownership of that object. If a function isn't supposed to take ownership, then it shouldn't be taking a smart pointer at all; use a reference (T&) or if you have need of nullability, a pointer but never store it.
If you are passing someone a unique_ptr, you are giving them ownership. Which means, by the nature of unique ownership, you are losing ownership of the memory. Thus, there's almost no reason to ever pass a unique_ptr by anything except by value.
Similarly, if you want to share ownership of some object, you pass in a shared_ptr. Whether you do it by reference or by value is up to you. Since you're sharing ownership, it's going to make a copy anyway (presumably), so you might as well take it by value. The function can use std::move to move it into class members or the like.
If the function isn't going to modify or make a copy of the pointer, just use a dumb pointer instead. Smart pointers are used to control the lifetime of an object, but the function isn't going to change the lifetime so it doesn't need a smart pointer, and using a dumb pointer gives you some flexibility in the type used by the caller.
void function(std::string * ptr);
function(my_unique_ptr.get());
function(my_shared_ptr.get());
function(my_dumb_ptr);
unique_ptr can't be copied without invalidating the original, so if you must pass it you must pass a reference.
For a more in-depth look at this recommendation by someone a lot smarter than me, see Herb Sutter's GotW #91 Solution: Smart Pointer Parameters. He goes beyond this recommendation and suggests that if the pointer can't be null, you should pass by reference instead of pointer. This requires dereferencing the pointer at the site of the call.
void function(std::string & val);
assert(my_unique_ptr != nullptr && my_shared_ptr != nullptr && my_dumb_ptr != nullptr);
function(*my_unique_ptr);
function(*my_shared_ptr);
function(*my_dumb_ptr);
A smart pointer is an object that refer to another object an manages its lifetime.
Passing a smart pointer reuquires to respect the semantics the smart poitner support:
Passing as const smartptr<T>& always work (and you cannot change the pointer, but can change the state of what it points to).
Passing as smartptr<T>& always work (and you can change the pointer as well).
Passing as smartptr<T> (by copy) works only if smartptr is copyable. It works with std::shared_ptr, but not with std::unique_ptr, unless you "move" it on call, like in func(atd::move(myptr)), thus nullifying myptr, moving the pointer to the passed parameter. (Note that move is implicit if myptr is temporary).
Passing as smartptr<T>&& (by move) imposes the pointer to be moved on call, by forcing you to explicitly use std::move (but requires "move" to make sense for the particular pointer).
I know the person asked this question is more knowledgeable than me in C++ and There are some perfect answer to this question but I believe This question better be answer in a way that it doesn't scares people from C++, although it could get a little complicated, and this is my try:
Consider there is only one type of smart pointer in C++ and it is shared_ptr, so we have these options to pass it to a function:
1 - by value : void f(std::shared_ptr<Object>);
2 - by reference : void f(std::shared_ptr<Object>&);
The biggest difference is ,the First one lend you the ownership and The second one let you manipulate the ownership.
further reading and details could be at this link which helped me before.

How to pass smart pointers in function?

In the following example, when I pass p to a function, It gets destroyed as soon as the function func exits
void func(std::auto_ptr<int> p)
{
// deletes p
}
int main()
{
std::auto_ptr<int> p(new int);
func(p);
*p = 1; // run-time error
}
I'm also told that passing smart pointers by reference is very bad design from the book "The C++ Standard Library - Reference by Nicolai M. Josuttis".
Quote:
Allowing an auto_ptr to pass by reference is very bad design and you
should always avoid it .....
..... According to the concept of auto_ptrs, it is possible to transfer ownership into a function by using a constant reference.
Is it not possible to pass smart pointers or have I got the wrong idea?
Is it not possible to pass smart pointers or have I got the wrong idea?
It only applies to auto_ptr. Also, as per the new C++11 standard auto_ptr is deprecated and unique_ptr is the superior alternative if you are using c++11.
The auto_ptr template class ensures that the object to which it points gets destroyed automatically when control leaves a scope, If you pass auto_ptr by value in a function, the object is deleted once the scope of the function ends. So essentially you transfer the ownership of the pointer to the function and you don't own the pointer beyond the function call.
Passing an auto_ptr by reference is considered a bad design because auto_ptr was specifically designed for transfer of ownership and passing it by reference means that the function may or may not take over the ownership of the passed pointer.
In case of unique_ptr, If you pass an unique_ptr to function by value then you are transferring the ownership of the unique_ptr to the function.
In case you are passing a reference of unique_ptr to the function if, You just want the function to use the pointer but you do not want to pass it's ownership to the function.
shared_ptr operates on a reference counting mechanism, so the count is always incremented when copying functions are called and decremented when a call is made to destructor.
Passing a shared_ptr by reference avoids calls to either and hence it can be passed by reference. While passing it by value appropriately increments and decrements the count, the copy constructor for shared_ptr is not very expensive for most cases but it might matter in some scenarios, So using either of the two depends on the situation.
You cannot pass a std::auto_ptr, but you can pass a smart pointer that manages the number of references to it, like boost::shared_ptr.

Operator & and * at function prototype in class

I'm having a problem with a class like this:
class Sprite {
...
bool checkCollision(Sprite &spr);
...
};
So, if I have that class, I can do this:
ball.checkCollision(bar1);
But if I change the class to this:
class Sprite {
...
bool checkCollision(Sprite* spr);
...
};
I have to do this:
ball.checkCollision(&bar1);
So, what's the difference?? It's better a way instead other?
Thank you.
In both cases you are actually passing the address of bar1 (and you're not copying the value), since both pointers (Sprite *) and references (Sprite &) have reference semantics, in the first case explicit (you have to explicitly dereference the pointer to manipulate the pointed object, and you have to explicitly pass the address of the object to a pointer parameter), in the second case implicit (when you manipulate a reference it's as if you're manipulating the object itself, so they have value syntax, and the caller's code doesn't explicitly pass a pointer using the & operator).
So, the big difference between pointers and references is on what you can do on the pointer/reference variable: pointer variables themselves can be modified, so they may be changed to point to something else, can be NULLed, incremented, decremented, etc, so there's a strong separation between activities on the pointer (that you access directly with the variable name) and on the object that it points to (that you access with the * operator - or, if you want to access to the members, with the -> shortcut).
References, instead, aim to be just an alias to the object they point to, and do not allow changes to the reference itself: you initialize them with the object they refer to, and then they act as if they were such object for their whole life.
In general, in C++ references are preferred over pointers, for the motivations I said and for some other that you can find in the appropriate section of C++ FAQ.
In terms of performance, they should be the same, because a reference is actually a pointer in disguise; still, there may be some corner case in which the compiler may optimize more when the code uses a reference instead of a pointer, because references are guaranteed not to change the address they hide (i.e., from the beginning to the end of their life they always point to the same object), so in some strange case you may gain something in performance using references, but, again, the point of using references is about good programming style and readability, not performance.
A reference cannot be null. A pointer can.
If you don't want to allow passing null pointers into your function then use a reference.
With the pointer you need to specifically let the compiler know you want to pass the address of the object, with a reference, the compiler already knows you want the ptr. Both are ok, it's a matter of taste, I personally don't like references because I like to see whats going on but thats just me.
They both do the (essentially) same thing - they pass an object to a function by reference so that only the address of the object is copied. This is efficient and means the function can change the object.
In the simple case you give they are equivalent.
Main differences are that the reference cannot be null, so you don't have to test for null in the function - but you also cannot pass a null object if the case of no object is valid.
Some people also dislike the pass by reference version because it is not obvious in the calling code that the object you pass in might be modified. Some coding standards recommend you only pass const references to functions.