Does it make sense to move onto function reference param - c++

void foo(const std::string& str);
foo(std::move(localstr));
If I know that I won't use this string anymore, will I have any gain by moving it if the function expects reference?
In general, there are so many advices now on the web for using parameters by value to be able to gain from moves, but I can't really find any practical usage of this so far. For me it seems that I still better declare my functions as const or non-const references.

If the variable is a std string, moving it there will do nothing until the API changes.
If the variable can be converted to a std string, moving it could be more efficient if there is an rvalue conversion constructor.
std move is a cast to an rvalue reference, and does not actually move. It gives permission for code to move it, but it only happens if that offer is taken up.

Related

Passing argument by r-value reference to constructor that accept const ref

I got a dispute with my colleague.
We have following example:
class Key
{
public:
Key() {}
Key(Key&& ) {}
Key(const Key& ) {}
};
class KeyWrapper
{
public:
KeyWrapper(const Key& key) : _key(key) {}
private:
Key _key;
};
int main()
{
Key key;
KeyWrapper wrapper(std::move(key));
return 0;
}
My point that in line KeyWrapper wrapper(std::move(key)); std::move has no effect, because KeyWrapper constructor accepts const ref and therefore std::move can be omitted. And inside of this constructor we can't write _key(std::move(key)), because we have constant reference to input parameter.
But my colleague says that std::move() should be in line KeyWrapper wrapper(std::move(key)); and also we should write _key(std::move(key)).
Please, judge us...
Here's my take.
If logically a move is the proper thing to do at the call site (in this case main()), you should move it. If the code receiving the object does not handle moves, reverting to c++98-style copies, that's a valid implementation of a move (but not optimized.) There is still no problem. Down the road, if the object begins accepting rvalue references or gains a forwarding-ref interface, you will benefit from the move improvements without having to go back and fix your calling code to take advantage of the change.
However, in a function receiving key as a const &, it should never move its argument. There is no justification for this, because you do not know anything about the caller, and cannot assume it is a safe thing to do.
Some classes are "safe to use after move" because move does not actually modify the source object, however, relying on this is really a bad idea as it depends on implementation details that are subject to change without warning, and is really just doing it wrong.
Here's some guidelines for when to move or not:
If a function receives an lvalue reference, it must never move it
If a function receives an object by value, it is safe to move
If a function receives an rvalue reference, it is safe to move
If a function receives a "forwarding reference" (a template function taking T&&) then it is not safe to move, but is safe to forward.
Notice, the rules above do not change based on knowledge that the underlying type is known to have identical behavior when moved and copied. For example, a trivial class containing only primitive data is technically safe to move even from a const& because moving it doesn't modify the source. However, do not do that because it has no benefit and is depending on something you might not control (or realize has changed.) It also make it look as though you are confused about move semantics, and will cause people to doubt the robustness of the rest of the design.
If you are in a controlled environment where you intimately know the caller and callee code are working together, and they are private without outside code using them, you may feel safe to relax some of these rules--but I still do not recommend it because it's harder to reason about when your code does odd things that break convention, and there is still little/no benefit.

clang-tidy suggest I remove const references, why?

I ran clang-tidy (the "modernize" modules) on a project tree that I have been trying to keep reasonably up to date with C++17. Almost everything it corrected was unsurprising to me, except for one thing: It changed all of these types of constructs:
void foo(const std::string& str) {
}
.. to this:
void foo(std::string str) {
}
And I don't understand why. To my untrained eye this would mean two things:
It would need to copy the object rather than just pass a reference. (Though I assume there are situations when the compiler can deduce that it can just pass a pointer when it generates the code -- but the reference makes it explicit (which is better imho)).
The const is there to tell the function body developer that it shouldn't be changing the input string, and that if it needs to modify the string it needs to store its own copy somewhere.
I do see an upside though -- by just passing an object as a const reference it's a mere "remove const" cast away from being changed anyway, so I guess passing by value would solve that.
Why does it recommend removing const references with non-const pass-by-values?
The rationale given here is
With move semantics added to the language and the standard library updated with move constructors added for many types it is now interesting to take an argument directly by value, instead of by const-reference, and then copy. This check allows the compiler to take care of choosing the best way to construct the copy.
Additionally
The transformation is usually beneficial when the calling code passes an rvalue and assumes the move construction is a cheap operation.
However, the documentation states that the only replacement is in the following specific case:
Replaces the uses of const-references constructor parameters that are copied into class fields. The parameter is then moved with std::move().
It doesn't even apply the transformation if the constructor parameter is used more than once.
So I don't think all your functions should have been transformed like that.

Would Move Semantic in C++ 11 be executed if there is no rvalue parameter with function signature?

To make program run more efficiently, move semantic is introduced since C++ 11, for example:
void fun(const string& str); //1st
void fun(string&& str); //2nd since c++ 11
If I use it like fun("tmpStr");, the 2nd function signatured with rvalue would be used,and it is more efficient than the 1st function.
But the problem is that if I need ONLY 1 function signature to handle paramters with both lvalue and rvalue, what shoud I do?
if the 1st one is kept, it is not efficient with rvalue;
if the 2nd one is kept, it is efficient with rvalue, but I have to fun(std::move(lvalue)) to make it possible with lvalue, which I think the added codes std::move looks like redundant---moreover, this makes the status of lvalue undefined after this function.
With the thought above, I wonder if Move Semantic in C++ 11 would be executed if there is no rvalue parameter with function signature like the 1st one, even just in release(optimized) mode?
if the answer is not , then what is the reason behind it?
Move semantics is irrelevant in this case because you don't want to modify the argument.
"tmpStr" is not a std::string, it is a const char*. Since you are taking a non-(const lvalue) reference to std::string, the compiler has to create a std::string somewhere. Allocation overhead is already incurred. Then, which reference you use really doesn't matter if you don't modify the temporary string. The best way to write the function is:
void fun(std::string_view sv)
This automatically handles string literals and std::strings, etc., and incurs zero allocation overhead. This is more efficient than moving. No move semantics involved.

Pass by value vs pass by rvalue reference

When should I declare my function as:
void foo(Widget w);
as opposed to:
void foo(Widget&& w);?
Assume this is the only overload (as in, I pick one or the other, not both, and no other overloads). No templates involved. Assume that the function foo requires ownership of the Widget (e.g. const Widget& is not part of this discussion). I'm not interested in any answer outside the scope of these circumstances. (See addendum at end of post for why these constraints are part of the question.)
The primary difference that my colleagues and I can come up with is that the rvalue reference parameter forces you to be explicit about copies. The caller is responsible for making an explicit copy and then passing it in with std::move when you want a copy. In the pass by value case, the cost of the copy is hidden:
//If foo is a pass by value function, calling + making a copy:
Widget x{};
foo(x); //Implicit copy
//Not shown: continues to use x locally
//If foo is a pass by rvalue reference function, calling + making a copy:
Widget x{};
//foo(x); //This would be a compiler error
auto copy = x; //Explicit copy
foo(std::move(copy));
//Not shown: continues to use x locally
Other than forcing people to be explicit about copying and changing how much syntactic sugar you get when calling the function, how else are these different? What do they say differently about the interface? Are they more or less efficient than one another?
Other things that my colleagues and I have already thought of:
The rvalue reference parameter means that you may move the argument, but does not mandate it. It is possible that the argument you passed in at the call site will be in its original state afterwards. It's also possible the function would eat/change the argument without ever calling a move constructor but assume that because it was an rvalue reference, the caller relinquished control. Pass by value, if you move into it, you must assume that a move happened; there's no choice.
Assuming no elisions, a single move constructor call is eliminated with pass by rvalue.
The compiler has better opportunity to elide copies/moves with pass by value. Can anyone substantiate this claim? Preferably with a link to gcc.godbolt.org showing optimized generated code from gcc/clang rather than a line in the standard. My attempt at showing this was probably not able to successfully isolate the behavior: https://godbolt.org/g/4yomtt
Addendum: why am I constraining this problem so much?
No overloads - if there were other overloads, this would devolve into a discussion of pass by value vs a set of overloads that include both const reference and rvalue reference, at which point the set of overloads is obviously more efficient and wins. This is well known, and therefore not interesting.
No templates - I'm not interested in how forwarding references fit into the picture. If you have a forwarding reference, you call std::forward anyway. The goal with a forwarding reference is to pass things as you received them. Copies aren't relevant because you just pass an lvalue instead. It's well known, and not interesting.
foo requires ownership of Widget (aka no const Widget&) - We're not talking about read-only functions. If the function was read-only or didn't need to own or extend the lifetime of the Widget, then the answer trivially becomes const Widget&, which again, is well known, and not interesting. I also refer you to why we don't want to talk about overloads.
What do rvalue usages say about an interface versus copying?
rvalue suggests to the caller that the function both wants to own the value and has no intention of letting the caller know of any changes it has made. Consider the following (I know you said no lvalue references in your example, but bear with me):
//Hello. I want my own local copy of your Widget that I will manipulate,
//but I don't want my changes to affect the one you have. I may or may not
//hold onto it for later, but that's none of your business.
void foo(Widget w);
//Hello. I want to take your Widget and play with it. It may be in a
//different state than when you gave it to me, but it'll still be yours
//when I'm finished. Trust me!
void foo(Widget& w);
//Hello. Can I see that Widget of yours? I don't want to mess with it;
//I just want to check something out on it. Read that one value from it,
//or observe what state it's in. I won't touch it and I won't keep it.
void foo(const Widget& w);
//Hello. Ooh, I like that Widget you have. You're not going to use it
//anymore, are you? Please just give it to me. Thank you! It's my
//responsibility now, so don't worry about it anymore, m'kay?
void foo(Widget&& w);
For another way of looking at it:
//Here, let me buy you a new car just like mine. I don't care if you wreck
//it or give it a new paint job; you have yours and I have mine.
void foo(Car c);
//Here are the keys to my car. I understand that it may come back...
//not quite the same... as I lent it to you, but I'm okay with that.
void foo(Car& c);
//Here are the keys to my car as long as you promise to not give it a
//paint job or anything like that
void foo(const Car& c);
//I don't need my car anymore, so I'm signing the title over to you now.
//Happy birthday!
void foo(Car&& c);
Now, if Widgets have to remain unique (as actual widgets in, say, GTK do) then the first option cannot work. The second, third and fourth options make sense, because there's still only one real representation of the data. Anyway, that's what those semantics say to me when I see them in code.
Now, as for efficiency: it depends. rvalue references can save a lot of time if Widget has a pointer to a data member whose pointed-to contents can be rather large (think an array). Since the caller used an rvalue, they're saying they don't care about what they're giving you anymore. So, if you want to move the caller's Widget's contents into your Widget, just take their pointer. No need to meticulously copy each element in the data structure their pointer points to. This can lead to pretty good improvements in speed (again, think arrays). But if the Widget class doesn't have any such thing, this benefit is nowhere to be seen.
Hopefully that gets at what you were asking; if not, I can perhaps expand/clarify things.
The rvalue reference parameter forces you to be explicit about copies.
Yes, pass-by-rvalue-reference got a point.
The rvalue reference parameter means that you may move the argument, but does not mandate it.
Yes, pass-by-value got a point.
But that also gives to pass-by-rvalue the opportunity to handle exception guarantee: if foo throws, widget value is not necessary consumed.
For move-only types (as std::unique_ptr), pass-by-value seems to be the norm (mostly for your second point, and first point is not applicable anyway).
EDIT: standard library contradicts my previous sentence, one of shared_ptr's constructor takes std::unique_ptr<T, D>&&.
For types which have both copy/move (as std::shared_ptr), we have the choice of the coherency with previous types or force to be explicit on copy.
Unless you want to guarantee there is no unwanted copy, I would use pass-by-value for coherency.
Unless you want guaranteed and/or immediate sink, I would use pass-by-rvalue.
For existing code base, I would keep consistency.
Unless the type is a move-only type you normally have an option to pass by reference-to-const and it seems arbitrary to make it "not part of the discussion" but I will try.
I think the choice partly depends on what foo is going to do with the parameter.
The function needs a local copy
Let's say Widget is an iterator and you want to implement your own std::next function. next needs its own copy to advance and then return. In this case your choice is something like:
Widget next(Widget it, int n = 1){
std::advance(it, n);
return it;
}
vs
Widget next(Widget&& it, int n = 1){
std::advance(it, n);
return std::move(it);
}
I think by-value is better here. From the signature you can see it is taking a copy. If the caller wants to avoid a copy they can do a std::move and guarantee the variable is moved from but they can still pass lvalues if they want to.
With pass-by-rvalue-reference the caller cannot guarantee that the variable has been moved from.
Move-assignment to a copy
Let's say you have a class WidgetHolder:
class WidgetHolder {
Widget widget;
//...
};
and you need to implement a setWidget member function. I'm going to assume you already have an overload that takes a reference-to-const:
WidgetHolder::setWidget(const Widget& w) {
widget = w;
}
but after measuring performance you decide you need to optimize for r-values. You have a choice between replacing it with:
WidgetHolder::setWidget(Widget w) {
widget = std::move(w);
}
Or overloading with:
WidgetHolder::setWidget(Widget&& widget) {
widget = std::move(w);
}
This one is a little bit more tricky. It is tempting choose pass-by-value because it accepts both rvalues and lvalues so you don't need two overloads. However it is unconditionally taking a copy so you can't take advantage of any existing capacity in the member variable. The pass by reference-to-const and pass by r-value reference overloads use assignment without taking a copy which might be faster
Move-construct a copy
Now lets say you are writing the constructor for WidgetHolder and as before you have already implemented a constructor that takes an reference-to-const:
WidgetHolder::WidgetHolder(const Widget& w) : widget(w) {
}
and as before you have measured peformance and decided you need to optimize for rvalues. You have a choice between replacing it with:
WidgetHolder::WidgetHolder(Widget w) : widget(std::move(w)) {
}
Or overloading with:
WidgetHolder::WidgetHolder(Widget&& w) : widget(std:move(w)) {
}
In this case, the member variable cannot have any existing capacity since this is the constructor. You are move-constucting a copy. Also, constructors often take many parameters so it can be quite a pain to write all the different permutations of overloads to optimize for r-value references. So in this case it is a good idea to use pass-by-value, especially if the constructor takes many such parameters.
Passing unique_ptr
With unique_ptr the efficiency concerns are less important given that a move is so cheap and it doesn't have any capacity. More important is expressiveness and correctness. There is a good discussion of how to pass unique_ptr here.
When you pass by rvalue reference object lifetimes get complicated. If the callee does not move out of the argument, the destruction of the argument is delayed. I think this is interesting in two cases.
First, you have an RAII class
void fn(RAII &&);
RAII x{underlying_resource};
fn(std::move(x));
// later in the code
RAII y{underlying_resource};
When initializing y, the resource could still be held by x if fn doesn't move out of the rvalue reference. In the pass by value code, we know that x gets moved out of, and fn releases x. This is probably a case where you would want to pass by value, and the copy constructor would likely be deleted, so you wouldn't have to worry about accidental copies.
Second, if the argument is a large object and the function doesn't move out, the lifetime of the vectors data is larger than in the case of pass by value.
vector<B> fn1(vector<A> &&x);
vector<C> fn2(vector<B> &&x);
vector<A> va; // large vector
vector<B> vb = fn1(std::move(va));
vector<C> vc = fn2(std::move(vb));
In the example above, if fn1 and fn2 don't move out of x, then you will end up with all of the data in all of the vectors still alive. If you instead pass by value, only the last vector's data will still be alive (assuming vectors move constructor clears the sources vector).
One issue not mentioned in the other answers is the idea of exception-safety.
In general, if the function throws an exception, we would ideally like to have the strong exception guarantee, meaning that the call has no effect other than raising the exception. If pass-by-value uses the move constructor, then such an effect is essentially unavoidable. So an rvalue-reference argument may be superior in some cases. (Of course, there are various cases where the strong exception guarantee isn't achievable either way, as well as various cases where the no-throw guarantee is available either way. So this is not relevant in 100% of cases. But it's relevant sometimes.)
Choosing between by-value and by-rvalue-ref, with no other overloads, is not meaningful.
With pass by value the actual argument can be an lvalue expression.
With pass by rvalue-ref the actual argument must be an rvalue.
If the function is storing a copy of the argument, then a sensible choice is between pass-by-value, and a set of overloads with pass-by-ref-to-const and pass-by-rvalue-ref. For an rvalue expression as actual argument the set of overloads can avoid one move. It's an engineering gut-feeling decision whether the micro-optimization is worth the added complexity and typing.
One notable difference is that if you move to an pass-by-value function:
void foo(Widget w);
foo(std::move(copy));
compiler must generate a move-constructor call Widget(Widget&&) to create the value object. In case of pass-by-rvalue-reference no such call is needed as the rvalue-reference is passed directly to the method. Usually this does not matter, as move constructors are trivial (or default) and are inlined most of the time.
(you can check it on gcc.godbolt.org -- in your example declare move constructor Widget(Widget&&); and it will show up in assembly)
So my rule of thumb is this:
if the object represents a unique resource (without copy semantics) I prefer to use pass-by-rvalue-reference,
otherwise if it logically makes sense to either move or copy the object, I use pass-by-value.

Is it possible to disallow taking a reference to an object

I want to do the opposite of making instances of a class noncopyable, that is, make sure that instances of a particular class can be passed only as a copy and not as a reference. If any function tries to receive it by reference, I would like it to give a compilation error (ideally) or a run time error.
I dont think making operator & private is going to do it, is there a legitimate way of doing this.
That's impossible. Any named variable can bind to a reference variable of the appropriate type. That's just how the language works.
In particular, you could never have a copy constructor with your restriction, so you couldn't actually pass the object by value!
I dont think making operator & private is going to do it, is there a legitimate way of doing this.
No, because the & you use in function signatures for pass-by-reference is not an operator. You're talking either about the address-of operator (unary) or bitwise-and operator (binary). So it has nothing to do with pass-by-reference.
There's no way to disallow pass-by-reference for a type.
I doubt your motivation is strong enough to do this, and you appear to have a bad understanding of the passing mechanism:
If any function tries to receive it by reference, I would like it to give a compilation error (ideally) or a run time error.
A function either passes a parameter by reference, or by value. It's decided by its declaration, and I think your confusion stems from here. For example:
void foo(X x);
takes the parameter x by value. There's no way to pass it by reference. No way. Likewise:
void foo(X& x)
takes it by reference, and it always will.