Quoting from The C++ Programming Language
(by Bjarne Stroustrup), page 1213
The thread constructors are
variadic templates
(§28.6). This implies that to pass a reference to a thread constructor, we must use a reference wrapper (§33.5.1).For example:
void my_task(vector<double>& arg); void test(vector<double>& v) { thread my_thread1 {my_task,v}; //oops: pass a copy of v thread my_thread2 {my_task,ref(v)}; // OK: pass v by reference thread my_thread3 {[&v]{ my_task(v); }}; // OK: dodge the ref() problem // ... }
The problem is that variadic templates
have no problem to pass arguments by reference to a target function.
For example:
void g(int& t)
{
}
template <class... T>
void f(T&&... t)
{
g(std::forward<T>(t)...);
}
int main()
{
int i;
f(i);
return 0;
}
The only reason that std::thread
passes by value is because the standard requires to use std::decay
on the arguments.
Am I correct?
Can somebody please explain this quote by Stroustrup?
Passing by reference by default would be a major foot-gun: when the thread accesses local variables, they may well be out of scope by the time that the thread runs, and it would have only dangling references. To make the use of values safer, the code must specify explicitly which variables are safe to access by reference in one of the ways that you showed.