Search code examples
c++referencestdthread

Why std::thread() passes arguments by value (and why the reason given by Dr. Stroustrup is incorrect)?


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?


Solution

  • 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.