Passing object by reference to std::thread in C++11
Solution 1:
Explicitly initialize the thread with a reference_wrapper
by using std::ref
:
auto thread1 = std::thread(SimpleThread, std::ref(a));
(or std::cref
instead of std::ref
, as appropriate). Per notes from cppreference on std:thread
:
The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g. with
std::ref
orstd::cref
).
Solution 2:
Based on this comment, this answer elaborates on the reason why the arguments are not passed by reference to the thread function by default.
Consider the following function SimpleThread()
:
void SimpleThread(int& i) {
std::this_thread::sleep_for(std::chrono::seconds{1});
i = 0;
}
Now, imagine what would happen if the following code compiled (it does not compile):
int main()
{
{
int a;
std::thread th(SimpleThread, a);
th.detach();
}
// "a" is out of scope
// at this point the thread may be still running
// ...
}
The argument a
would be passed by reference to SimpleThread()
. The thread may still be sleeping in the function SimpleThread()
after the variable a
has already gone out of scope and its lifetime has ended. If so, i
in SimpleThread()
would actually be a dangling reference, and the assignment i = 0
would result in undefined behaviour.
By wrapping reference arguments with the class template std::reference_wrapper
(using the function templates std::ref
and std::cref
) you explicitly express your intentions.
Solution 3:
std::thread
copy(/move) its arguments, you might even see the note:
The arguments to the thread function are moved or copied by value. If a reference argument needs to be passed to the thread function, it has to be wrapped (e.g., with
std::ref
orstd::cref
).
So, you might use std::reference_wrapper
through std::ref
/std::cref
:
auto thread1 = std::thread(SimpleThread, std::ref(a));
or use lambda:
auto thread1 = std::thread([&a]() { SimpleThread(a); });