3

Lets say I want to pass some reference argument to the thread - the standard only allows this by using std::ref.

Now lets consider this code that has undefined behaviour (see comments)

    void thread_fun(int& x) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        x = -2;
    }

    int main() {
        {
            int a = 10;
            std::thread t(thread_fun, std::ref(a));
            std::cout << "in main: " << a << '\n';
            t.detach();
        }
        // here thread t may still running and writing to an object "a" which
        // already destroyed is undefined behaviour
        return 0;
    }

Without using std::ref(a) it does not compile - is this some kind protection from undefined behaviour at compile time ?

If it is, then the big question for me is why are we allowed to pass raw pointers to std::thread ?

For example, I can rewrite the same code above to pass a pointer like so:

    void thread_fun(int* x) {
        std::this_thread::sleep_for(std::chrono::seconds(1));
        *x = -2;
    }
    //...
    {
        int a = 10;
        std::thread t(thread_fun, &a);
        //...
    }

And this also contains undefined behaviour, but no compile time protection here !?

What is special in case of passing references ??

ampawd
  • 968
  • 8
  • 26

2 Answers2

1

What is special in case of passing references ??

The special thing is that passing by reference looks identical at the call site to passing by value.

Every other case you show leaves at least a hint at the call site that you may be doing something risky, without having to read the function prototype.

Useless
  • 64,155
  • 6
  • 88
  • 132
0

is this some kind protection from undefined behaviour at compile time ?

It is not, by default thread takes arguments as copies (or moved)

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). https://en.cppreference.com/w/cpp/thread/thread/thread

thus as pointed, references needs to be "shown" in some way.

Pointer are not treated differently, they are just copied.

The undefined behavior is not caught by compiler here (enven if maybe it could) because using a reference does not alway mean undefined behavior here, depending on you construct (if you do not detach, but join, it would be ok).

This is the same for pointer, it may come from a global or a new which would be ok.

OznOg
  • 4,440
  • 2
  • 26
  • 35