13

Is std::move necessary in the following snippet?

std::function<void(int)> my_std_function;

void call(std::function<void(int)>&& other_function)
{
  my_std_function.swap(std::move(other_function));
}

As far as I know call() accepts a rvalue reference.. but since the rvalue reference is itself an lvalue, in order to call swap(std::function<void(int)>&&) I have to re-cast this to an rvalue reference with std::move

Is my reasoning correct or std::move can be omitted in this case (and if it can, why?)

1
  • 1
    Seems like you want to issue operator= instead of swap here. And then, yes, use move. Commented Jan 4, 2016 at 15:06

4 Answers 4

18

std::function::swap does not take its parameter by rvalue reference. It's just a regular non-const lvalue reference. So std::move is unhelpful (and probably shouldn't compile, since rvalue references aren't allowed to bind to non-const lvalue references).

other_function also doesn't need to be an rvalue reference.

Sign up to request clarification or add additional context in comments.

Comments

11

The signature is

void std::function<Sig>::swap( function& other )

so code should not compile with std::move (msvc has extension to allow this binding :/)

As you take r-value reference, I think that a simple assignment is what you want in your case:

std::function<void(int)> my_std_function;

void call(std::function<void(int)>&& other_function)
{
  my_std_function = std::move(other_function); // Move here to avoid copy
}

2 Comments

@Dean would this magic include turning a very fast computer into a hot block of plastic merely by installing it?
@Dean Er, what? Why is it "fantastic magic" to allow rvalue refs to bind to non-const lvalue refs? Was that sarcasm?
3

In this case, it doesn't make a difference as std::function::swap takes a non-const lvalue reference. It shouldn't even compile with std::move.

If you used a function which did allow rvalues, then you would need to call std::move as other_function is an lvalue, even though the type of it is an rvalue reference. For example:

struct Foo {
    Foo()=default;
    Foo(const Foo&) { std::cout << "copy" << std::endl; }
    Foo(Foo&&) { std::cout << "move" << std::endl; }
};

void bar (Foo&& a) {
    Foo b {a};            //copy
    Foo c {std::move(a)}; //move
}

1 Comment

This adds valuable information instead of just mentioning that swap() takes a reference, which I think wasn't really the point of the question.
1

You are right in a sense — to get an rvalue again you'd need std::move.

However, the swap call doesn't need an rvalue or an rvalue reference — just a plain ol' lvalue ref.

So you're good to go without the std::move cast.

In terms of move semantics, a swap operation is pretty low-level. You'll find that most useful moves are ultimately implemented by a series of swaps, so it makes sense that the swaps themselves don't use move semantics. Really, how would they?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.