Reputation: 3111
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
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
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 int
s 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();
Upvotes: 3