1
votes

I am learning C++11 threads and facing problems in compiling the below program.

I am unable to figure out the problem as everything seems correct.

#include <iostream>
#include <thread>
#include <unistd.h>

using namespace std;

void hello(string& s)
{
  s = "HELLO";
  cout << "Hello thread created" << endl;
}

int main()
{
  cout << "main thread created" << endl;
  string s = "HEY";
  thread t(hello, s);
  t.join();
  cout << s << endl;

  return 0;
}   

My g++ version is 4.8.5 and I am compiling it on CentOS-7.2 using command :

g++ thread.cpp -std=c++11 -pthread

The error I am getting is:

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

Any help would be highly appreciated.

1
From en.cppreference.com/w/cpp/thread/thread/thread (see the notes) '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). 'john

1 Answers

3
votes

std::thread keeps a copy of the objects that it will pass to the thread function, and when it starts the new thread it passes those arguments to the thread as rvalues. Non-const lvalue-references references cannot bind to rvalues, so the parameter for your hello function cannot be bound to the object std::thread tries to pass to it.

If you want to avoid this copying behavior, use std::reference_wrapper:

int main()
{
  cout << "main thread created" << endl;
  string s = "HEY";
  thread t(hello, std::ref(s));
  t.join();
  cout << s << endl;

  return 0;
}

std::reference_wrapper<T> is an object that holds a reference to an object, and, when copied, copies only the reference. It also has an implicit conversion to T&, so when std::thread passes the std::reference_wrapper<std::string> object to your hello function, it will be implicitly converted to a reference to the original object used to construct it in your main thread.