9

A quote from Nikolai Josuttis - Standard Library C++11:

Detached threads can easily become a problem if they use nonlocal resources. The problem is that you lose control of a detached thread and have no easy way to find out whether and how long it runs. Thus, make sure that a detached thread does not access any objects after their lifetime has ended. For this reason, passing variables and objects to a thread by reference is always a risk. Passing arguments by value is strongly recommended.

So further the author explains, that even if you pass a reference as a function argument to a thread, it still passes by value, so you must indicate the reference with std::ref.

I have these questions, see the code below:

void f(std::vector<int> V){...}
void g(std::vector<int>& V){...}

std::vector<int> V;

std::thread t1(f, V);
std::thread t2(f, std::ref(V));
std::thread t3(g, V);
std::thread t4(g, std::ref(V));

What are the differences in these 4 lines? Which lines are equivalent?
I am not joining or detaching thread, it's not about that, it's about the ways of passing the function argument.

6
  • 2
    Have you tried to run it? I believe modifying the value inside of the thread and printing it would show the difference perfectly (launch one by one). Commented May 21, 2018 at 16:04
  • 2
    Well, one of those will be ill-formed on a standard compliant compiler, I can tell you that. Commented May 21, 2018 at 16:07
  • 2
    @StoryTeller I would think so too, so I'm not at all surprised it actually still compiles with MS tool chain (CL 19.00.24215.1). Commented May 21, 2018 at 16:13
  • 2
    @WhozCraig - It's that damn extension that allows binding non-const lvalue reference to rvalues. Commented May 21, 2018 at 16:13
  • 2
    @StoryTeller ya. that's generally the very first thing I turn off on new projects. neglected to in this case. silly me. Commented May 21, 2018 at 16:14

1 Answer 1

9

t1:

This simply passes a copy of V to the thread.

t2:

Similarly to t1, a copy of V is passed to the thread, but the actual copy is made in the called thread instead of the caller thread. This is an important distinction because should V be altered or cease to exist by the time the thread begins, you will end up with either a different vector or Undefined Behavior.

t3:

This should fail to compile as the thread will move the vector into the LValue reference, which is supposed to be illegal.

t4:

This passes the vector by reference to the thread. Any modifications to the passed reference will be applied to V, provided that proper synchronisation is performed, of course.

Sign up to request clarification or add additional context in comments.

3 Comments

t2 and t1 are completely different.
@T.C. I was under the impression that the exception requirements of the conversion process for the thread arguments having to be in the caller thread implied that the copy would have to be made in the caller thread, and then the result moved into f once the actual thread starts, is that not correct?
As usual @T.C. is correct: ideone.com/2h58iM (though I'm not sure what I've missed here exactly), I'll ammend the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.