15
#include <thread>
#include <string>
#include <vector>
#include <chrono>

using namespace std;

void f(const vector<string>& coll)
{
    this_thread::sleep_for(1h);

    //
    // Is coll guaranteed to be valid before exiting this function?
    //
}

int main()
{
    {
        vector<string> coll(1024 * 1024 * 100);
        thread(f, coll).detach();
    }

    //
    // I know std::thread will copy arguments into itself by default, 
    // but I don't know whether these copied objects are still valid
    // after the std::thread object has been destroyed.
    //

    while (true);
}

Is it safe to pass arguments by reference into a std::thread function?

xmllmx
  • 39,765
  • 26
  • 162
  • 323
  • 1
    Short answer: Yes, it's completely safe and okay. – DeiDei Jan 05 '17 at 03:36
  • 7
    You aren't passing anything by reference to the thread. – T.C. Jan 05 '17 at 03:38
  • I apologize, you are correct; I misread the code. – Rafael Jan 05 '17 at 03:45
  • I misread the documentation, he is using construct 3, I glazed over it initially – Rafael Jan 05 '17 at 03:48
  • 1
    @T.C., I know `std::thread` will copy arguments into itself by default, but I don't know whether these copied objects are still valid after the `std::thread` object has been destroyed. – xmllmx Jan 05 '17 at 03:50
  • 1
    The `std::thread` object is no longer associated with the thread of execution because you `detach` from it. The `thread` itself will move the `vector` when calling `f`, that will bind to the `vector const&` parameter and its lifetime will end when `f` exits, so your code is safe. – Praetorian Jan 05 '17 at 04:13

2 Answers2

6

As @T.C.'s comment, you're not passing reference to thread, you just make a copy of the vector in the thread:

thread(f, coll).detach(); // It's NOT pass by reference, but makes a copy.

If you really want to pass by reference, you should write this:

thread(f, std::ref(coll)).detach(); // Use std::ref to pass by reference

Then the code will get segment fault if the thread tries to access the vector, since when the thread runs, it's very likely the vector is already destructed (because it went out of it's scope in the main program).

So to your question:

Is it safe to pass arguments by reference into a std::thread function?

  • It is safe if you're sure the object remains valid during the thread's running;
  • It is NOT safe if the object is destructed, and you will get segment fault.
G. Sliepen
  • 7,637
  • 1
  • 15
  • 31
Mine
  • 4,123
  • 1
  • 25
  • 46
3
  • Is coll guaranteed to be valid before exiting this function?

    • Updated: Yes. When you pass coll to the constructor of a std::thread in main function, because coll is an object, it is decay copied. This decay copy essentially moves the vector (so it becomes rvalue), which will bind to the coll parameter in f during the execution of the thread. (Thanks for the comment by @Praetorian)
  • Is it safe to pass arguments by reference into a std::thread function?

    • Your arguments are decay copied, so you actually never pass anything by reference to std::thread.
  • Reference for std::decay: http://www.cplusplus.com/reference/type_traits/decay/

  • The accepted answer in this question std::thread with movable, non-copyable argument explained what happens to the arguments passed to std::thread
Guy Avraham
  • 3,482
  • 3
  • 38
  • 50
volatilevar
  • 1,626
  • 14
  • 16
  • 3
    Can you elaborate what "`decay` copied" means? If it is not passed by reference, where/when is the copy made? Clearly a reference to the copy must be passed into `f` in OP's example. It might also be worth noting that lambdas still allow one to capture by reference without running into this decaying behavior. – jtbandes Jan 05 '17 at 04:33