0
#include <iostream>
#include <thread>

template<int Num>
class MyClass {
public:
    MyClass(int val) : val_(val) {}

    // Copy constructor
    MyClass(const MyClass& other) : val_(other.val_) {
        std::cout << "Copy constructor called" << std::endl;
    }

    // Move constructor
    MyClass(MyClass&& other) noexcept : val_(other.val_) {
        std::cout << "Move constructor called" << std::endl;
    }

private:
    int val_;
};

template<int Num>
void threadFunction(MyClass<Num> myObj) {
    std::cout << "Inside thread" << std::endl;
}

int main() {
    MyClass<1> obj(42);

    std::thread t1(threadFunction<1>, obj); // <-- pass by value
    std::thread t2(threadFunction<1>, std::ref(obj)); // <-- pass by reference

    t1.join();
    t2.join();

    return 0;
}

I want to pass an object by value to a thread to ensure each thread works on its own copy (thread t1).

When I create thread t2, I pass the object by reference using std::ref(obj).

Clearly, my intention per function definition is to pass the object by value rather than by reference. Is obj a shared variable if passed as std::ref(obj) among all threads?

This question std::ref using with template function and function passing by value seems to address a similar topic, but not in multithreading context. In the example shown there, there seems to be a difference if the function is templated.

EDIT 1:

I added a copy and move constructor to the class motivated by the discussion in the answer below.

2
  • The same reason you can assign a reference to an object? Having threads involved doesn't make any difference, you'd see the same behaviour without godbolt.org/z/8zhPn6W81 Commented Apr 26, 2024 at 6:59
  • @AlanBirtles, what do you mean by "assign a reference to an object?" Do you mean that you can write a=b where the type of a is T and the type of b is T&? Or, do I misunderstand you? I would call a=b an assignment of a value. The value is obtained from the location to which b refers, and it is assigned to (i.e., copied to) the location that is named by a. Commented Apr 26, 2024 at 15:31

1 Answer 1

5

Why would it not compile?

std::ref returns a std::reference_wrapper which has an implicit conversion to reference to stored object that is used here.

Is obj a shared variable if passed as std::ref(obj) among all threads?

No. Each thread gets a copy.

The situation is similar to

 void foo( int a) { std::cout << a; }

 int main() {
     int x = 42;
     int& ref = x;
     foo(ref);
 }

ref is a reference to x. When you call foo(ref) then a is a copy of x.

Actually the need to use std::ref arises because the thread constructor always gets its parameters by value. And if the function called by the thread is template <typename Num> void threadFunction(MyClass<Num> myObj), ie it accepts a value, then nothing can magically change it to get myObj passed by reference.

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

11 Comments

That said, when a thread function accepts its parameters by value, std::ref(arg) has no effect?
@Mathieu what do you think? What effect can it have?
Honestly, I am not sure. Is it more a performance issue?
@Mathieu its what I wrote in the answer. std::ref returns a std::reference_wrapper around the object, this is implicitly converted to a reference to the object, from that a copy is made. It is as-if you did not use std::ref. if you turn it on the optimizer will most likely notice that. However, imho "is there a performance issue" is the wrong question because using std::ref when there is no need to is not simple code. It confuses the reader, they might think it is pass by reference.
I see. I observed the following by adding Copy+Move constructor to the class. std::thread(threadFunction, obj)call both Copy+Move constructor, whereas std::thread(threadFunction, std::ref(obj)) calls only Copy constructor. I only have basis knowledge about that, but I think moving (large) objects is cheap compared to copying, right?
|

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.