Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does auto return type lose move semantics in this example?

I was watching the video where Nicolai says that auto loses move semantics for this example:

template<typename Callable, typename... Args>
auto call(Callable&& op, Args&&... args) {
return std::invoke(std::forward<Callable>(op), std::forward<Args>(args)...);
}

I was wondering:

  1. why is this the case?

  2. does guaranteed RVO kick in in this example? If so what is the point of worrying about move?

like image 488
NoSenseEtAl Avatar asked Feb 12 '18 12:02

NoSenseEtAl


People also ask

What is return value in C++ move semantics?

The return value is a rvalue reference to the object. Working of Move Semantics in C++ Whenever there is a need to move the contents of the objects between the objects instead of copying the contents from one object to another object, we make use of Move Semantics in C++.

How to move an object using move semantics in Java?

Then a move constructor is defined to initialize the move operation. Then the assignment of move operation is performed. Then getvarLength function is written which returns the length of the object. Then swap function to swap the content of the objects by making use of move semantics. Then getvarLength function returns the value of the object.

What is the difference between move semantics and copy semantics?

See my first answer for an example. Note that if an object does not manage at least one external resource (either directly, or indirectly through its member objects), move semantics will not offer any advantages over copy semantics. In that case, copying an object and moving an object means the exact same thing:

Is it possible to return an automatic object from a function?

For that reason, C++11 has a special rule that allows returning automatic objects from functions without having to write std::move. In fact, you should never use std::move to move automatic objects out of functions, as this inhibits the "named return value optimization" (NRVO). Never use std::move to move automatic objects out of functions.


1 Answers

I think Nicolai could have just phrased it a bit better.

When you return by auto, your function returns a value (the type of which will be deduced). If std::invoke returns a pure rvalue or an xvalue, then of course the result of call will be constructed accordingly (by a move, if possible). We don't "lose move semantics" in that sense.

But when we return by value, that value object needs to be created. It can be created by a move, and under certain circumstances (which aren't present here) it can be elided, but it must be created. Guaranteed copy elision doesn't allow us to cop out of creating this object.

That can be quite wasteful if std::invoke gives us back an xvalue (an rvalue reference to something). Why should we construct an object to return it?

That's why a slide or two later he says we should return by decltype(auto). The deduction rules will then preserve the value cateogry of the the call to std::invoke:

  1. If it returns a value, we are no worse off. Our own call will return a value (which it may create by moving the return value of std::invoke).

  2. If std::invoke returns an lvalue(X&) or an xvalue(X&&), that will be returned as is, without creating another object by a copy or move.

like image 89
StoryTeller - Unslander Monica Avatar answered Nov 15 '22 06:11

StoryTeller - Unslander Monica