#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); // <-- cally copy AND move
std::thread t2(threadFunction<1>, std::ref(obj)); // <-- calls only copy
t1.join();
t2.join();
return 0;
}
根据此处的答案,我知道在此示例中实际上不需要
std::ref(obj)
:
c++ 线程函数按值接受对象:为什么 std::ref(obj) 编译?
但是,根据 obj 的传递方式,会调用不同的构造函数:
obj
的复制+移动构造函数,以及std::ref(obj)
的仅复制构造函数。
这是为什么?
在
std::thread t1(threadFunction<1>, obj);
中,obj
首先被复制到 std::thread
(在当前线程上),以便当给定函数最终准备好被调用时,线程已准备好对象。
请注意,使用此构造函数具有以下效果
std::invoke(auto(std::forward<F>(f)), auto(std::forward<Args>(args))...)
副本是
auto(...)
的结果,它是一个右值。然后,当 MyClass
执行时,会调用 std::invoke
的移动构造函数,并传递给给定的函数。
另一方面
std::thread t2(threadFunction<1>, std::ref(obj)); // <-- calls only copy
线程在这里存储
std::reference_wrapper
而不是复制对象,因此构造函数不会在主线程上被调用。
然而,最终, std::invoke
被调用并调用复制构造函数,作为包装引用传递给函数的结果。