c++ 线程函数按值接受类对象:为什么调用移动构造函数?

问题描述 投票:0回答:1
#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)
的仅复制构造函数。

这是为什么?

c++ multithreading constructor move
1个回答
1
投票

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
被调用并调用复制构造函数,作为包装引用传递给函数的结果。

© www.soinside.com 2019 - 2024. All rights reserved.