Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing object by reference to std::thread in C++11

Why can't you pass an object by reference when creating a std::thread ?

For example the following snippit gives a compile error:

#include <iostream> #include <thread>  using namespace std;  static void SimpleThread(int& a)  // compile error //static void SimpleThread(int a)     // OK {     cout << __PRETTY_FUNCTION__ << ":" << a << endl; }  int main() {     int a = 6;      auto thread1 = std::thread(SimpleThread, a);      thread1.join();     return 0; } 

Error:

In file included from /usr/include/c++/4.8/thread:39:0,                  from ./std_thread_refs.cpp:5: /usr/include/c++/4.8/functional: In instantiation of ‘struct std::_Bind_simple<void (*(int))(int&)>’: /usr/include/c++/4.8/thread:137:47:   required from ‘std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(int&); _Args = {int&}]’ ./std_thread_refs.cpp:19:47:   required from here /usr/include/c++/4.8/functional:1697:61: error: no type named ‘type’ in ‘class std::result_of<void (*(int))(int&)>’        typedef typename result_of<_Callable(_Args...)>::type result_type;                                                              ^ /usr/include/c++/4.8/functional:1727:9: error: no type named ‘type’ in ‘class std::result_of<void (*(int))(int&)>’          _M_invoke(_Index_tuple<_Indices...>)          ^ 

I've changed to passing a pointer, but is there a better work around?

like image 328
austinmarton Avatar asked Dec 03 '15 23:12

austinmarton


People also ask

Can you pass a reference to a thread C++?

In c++11 to pass a referenceto a thread, we have std::ref(). std::thread t3(fun3, std::ref(x)); In this statement we are passing reference of x to thread t3 because fun3() takes int reference as a parameter. If we try to pass 'x' or '&x' it will throw a compile time error.

What will happen if passing reference through std :: thread?

If you have used std::thread or std::bind , you probably noticed that even if you pass a reference as parameter, it still creates a copy instead. From cppreference, The arguments to the thread function are moved or copied by value.

How do you pass an object in a thread?

You don't pass objects to threads; you allow their methods to be called in different threads. If you have immutable objects, no problem; they are implicitly thread‑safe. All object state is visible wherever the object is visible and there are accessible getXXX() methods permitting you to see the state.

How do you pass objects by references?

Pass-by-reference means to pass the reference of an argument in the calling function to the corresponding formal parameter of the called function. The called function can modify the value of the argument by using its reference passed in. The following example shows how arguments are passed by reference.


2 Answers

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 or std::cref).

like image 64
ShadowRanger Avatar answered Sep 29 '22 07:09

ShadowRanger


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.

like image 31
ネロク・ゴ Avatar answered Sep 29 '22 09:09

ネロク・ゴ