Ankit Acharya
Ankit Acharya

Reputation: 3111

using std::move in std::thread

I encountered yet another problem with std::thread & this time while applying std::move to swap 2 values. My code says :-

#include <iostream>
#include <thread>
using namespace std;
void swapno (int &&a, int &&b)
{
    int temp=move(a);
    a=move(b);
    b=move(temp);
}
int main()
{
    int x=5, y=7;
    cout << "x = " << x << "\ty = " << y << "\n";
//  swapno (move(x), move(y));  // this works fine
    thread t (swapno, move(x), move(y));
    t.join();
    cout << "x = " << x << "\ty = " << y << "\n";
    return 0;
}

Output :-

x = 5   y = 7
x = 5   y = 7

Now what's wrong in this method ? Why is such the code showing such a behaviour ? How do I correct it ?

Upvotes: 3

Views: 2728

Answers (2)

Werner Erasmus
Werner Erasmus

Reputation: 4076

In layman's terms, thread's constructor accepts temporaries/rvalues to the arguments passed to the function. Therefore you have to wrap it with a reference_wrapper, which is a value but wraps the underlying reference (what std::ref does).

The code below does the trick with std::swap out of the box. Using std::swap as argument to thread (or std::function) causes and ambiguous overload (which surprised me too).

int main(int argc, char* argv[])
{
  int x = 5, y = 7;
  std::cout << "x(" << x << ")" << " y(" << y <<")" << std::endl;
  void (*pf)(int& x, int& y) = std::swap<int>;
  std::thread t1(pf, std::ref<int>(x), std::ref<int>(y));
  t1.join();
  std::cout << "x(" << x << ")" << " y(" << y <<")" << std::endl;
  return 0;
}

Upvotes: 0

AndyG
AndyG

Reputation: 41092

It's because the thread constructor you're calling

copies/moves all arguments (both the function object f and all args...) to thread-accessible storage as if by the function:

template <class T>
typename decay<T>::type decay_copy(T&& v) {
    return std::forward<T>(v);
}

And std::decay will remove cv-qualifiers, which includes r-value references.

Thus, when std::thread is copy/moving arguments to thread-accessible storage, it's essentially move constructing it's own ints from the ones you provided, and because a move on an int is simply a copy, when you perform swapno on its values, you're doing it on copies.

To correct it, use std::ref plus swap:

std::thread t ([](int& a, int& b){std::swap(a, b);}, std::ref(x), std::ref(y));
t.join();

Live Demo

Upvotes: 3

Related Questions