2

I have two functions

void f(const int &x) {}
void g(int& x) {}

I can make

int x = 0;
std::thread t1(f, x);

But I can't create std::thread t2(g, x), in this case i need make std::ref(x) instead of just x, why is it necessary?

And why it possible to create t1 without std::cref?

463035818_is_not_an_ai
  • 109,796
  • 11
  • 89
  • 185
  • What exactly is the error message you get? – Tanveer Badar Feb 22 '21 at 18:21
  • 3
    `std::thread` copies the arguments to the function. `std::ref` wraps your object in a `std::reference_wrapper` which grants reference semantics, so copies refer to the original object. – François Andrieux Feb 22 '21 at 18:24
  • okay, I got it. But why `t1` is successfully created without `std::cref`? – Артём Гаркавый Feb 22 '21 at 18:27
  • 1
    The type information of all the involved parameters is important in C++. Please write out a compilable example that shows the issue. From this `std::thread t1(f, x)` it is impossible to tell because we don't know what `f` or `x` are! – Martin York Feb 22 '21 at 18:27
  • Full code https://ideone.com/KjOIKc. And it works also is case when I change `int` to any type. Why is it compile and does not requere pass `x` by `std::cref`? – Артём Гаркавый Feb 22 '21 at 18:31
  • @АртёмГаркавый If you don't use `std::ref` the original argument will just be copied to a different `int`. And an `int` is a perfectly valid object to bind to `const int &` so there is no error, except that you don't get the pass-by-reference behavior you expected. But the compiler is fine with that. – François Andrieux Feb 22 '21 at 18:34
  • Wow, it really copies. I try an example (https://ideone.com/5H80EI), and this cycle run infinitely, it really copies passes values, is it C++ bug? – Артём Гаркавый Feb 22 '21 at 18:44
  • @АртёмГаркавый Please include full code as a part of the question, **and** make sure the code is minimal. When asked to clarify, please *fix the question*, don't just add information in the comments. The question should be complete **with all comments removed**. In fact, comments are sometimes removed wholesale when they seem to be too chatty. So use comments as input to improve the question, but don't "leak" question into the comments. – Kuba hasn't forgotten Monica Feb 22 '21 at 19:27

1 Answers1

2

Your f() function does not work as you expect without std::cref().

Although f() does not intent to change the value behind x, it does not mean that the value behind this reference cannot be mutated elsewhere.

In this example, without std::cref() a copy of the original int is put in the thread stack, and x references this copy; we see 1 and 1.

On the other hand, with std::cref(), x still references the original; we see 1 and 2.

/**
  g++ -std=c++17 -o prog_cpp prog_cpp.cpp \
      -pedantic -Wall -Wextra -Wconversion -Wno-sign-conversion \
      -g -O0 -UNDEBUG -fsanitize=address,undefined -pthread
**/

#include <iostream>
#include <thread>

using namespace std::chrono_literals;
void
f(const int &x)
{
  std::cout << "x=" << x << '\n';
  std::this_thread::sleep_for(1000ms);
  std::cout << "x=" << x << '\n';
}

int
main()
{
  int i=1;
  // std::thread th{f, i}; // copy to thread stack
  std::thread th{f, std::cref(i)}; // reference the original i
  std::this_thread::sleep_for(500ms);
  i+=1;
  th.join();
  return 0;
}
prog-fh
  • 13,492
  • 1
  • 15
  • 30
  • Thanks! It's a pity that C++ by stealth will copy objects. BTW, why this code worked when I change std::cref to std::ref? Should the behavior be the same? – Артём Гаркавый Feb 22 '21 at 19:01
  • 1
    @АртёмГаркавый `x` is a reference on `const` thus providing a mutable reference wrapper does not harm. On the other hand, providing a const-reference wrapper where a reference on a mutable object is expected (`g()` in your question) would make the compiler complain. – prog-fh Feb 22 '21 at 19:05
  • @АртёмГаркавый *It's a pity that C++ by stealth will copy objects* There's a fine line between "stealth" and "not understanding enough about the fundamental semantics of C++". Those semantics aren't self-obvious, although they did arise in the design process of the language, and usually are a particular way because otherwise something "simple" would break or become even less obvious. That's what it means to become experienced with C++: such understanding is inherent to effective use of the language. A lot of stuff appears stealthy to a relative novice, no matter the programming language. – Kuba hasn't forgotten Monica Feb 22 '21 at 19:29