具有对象右值引用的线程

thread with rvalue reference of an object

我有一个接受对象右值引用的函数,我想 运行 在 std::thread 中使用这个函数。以下一段代码

#include <iostream>
#include <thread>

class MyType {
public:
    explicit MyType(int m) : myint_(m) {}
    MyType(const MyType& ) = delete;
    MyType ( MyType&& ) = delete;
    MyType operator = (const MyType& ) = delete;
    MyType operator = (const MyType&&) = delete;

private:
   int myint_;
};

void Run(const MyType&& t) {
  // do somthing with t.     
}

int main()
{
    MyType m{100};
    std::thread t(Run, std::move(m));
    t.join();
    return 0;
}

我删除了默认的移动和复制构造函数。在我的例子中,可以定义一个默认的移动构造函数,但我不希望有一个复制构造函数,因为 sizeof(MyType) 可能很大,而且我担心调用复制构造函数时的内存。

我需要有关如何实现此目标的建议。

此致。

发生的事情是 std::thread 将其参数复制到类似元组的内容中,然后在线程中使用这些参数调用函数。

在您的特定情况下,线程不会超过创建 std::thread 对象的范围。这不是典型的。

获得您想工作的最简单方法是:

MyType m{100};
std::thread t([&]{ Run(std::move(m)); });
t.join();

在其中传递 lambda 并自行管理复制和生命周期。

请注意,如果此线程的生命周期超过了创建 m 的范围,这将遵循悬空引用。

std::thread t([pm=std::make_unique<MyType>(100)]() mutable { Run(std::move(*pm)); });

是我直接在堆上创建对象,然后使用智能指针随线程携带的版本。一个正确编写的 std::thread 应该只要求它的可调用对象是可移动的(一个错误编写的将它存储在一个标准函数中会在这里产生构建错误;你可以将唯一的 ptr 换成共享的 ptr 以获得适度的额外开销但让它编译在不符合标准的 std 线程上)。


我的一般经验法则是使用基于 INVOKE 的线程助手,而是使用无参数 lambda 并自己处理参数存储和传递。

线程API来自C++前lambda时代的boost; lambdas 是你无论如何都应该掌握的东西,并且可以取代必须在基于 INVOKE 的 API 的怪癖方面获得专业知识(即使知道 INVOKE 是什么你也不需要知道!)

(std::invoke, 和 std::apply, OTOH, 很棒,即使它们是 INVOKE;我的主要抱怨是违反了 SRP(单一责任原则),我们将线程构造与调用结构。)

感谢@SamVarshavchik 我现在可以使用 std::unique_ptr

#include <iostream>
#include <thread>

class MyType {
public:
    explicit MyType(int m) : myint_(m) {}
    MyType(const MyType& ) = delete;
    MyType ( MyType&& ) = delete;
    MyType operator = (const MyType& ) = delete;
    MyType operator = (const MyType&&) = delete;

private:
   int myint_;
};

void Run(std::unique_ptr<MyType>&& t) {
  // do somthing with t.     
}

int main()
{
    auto m = std::make_unique<MyType>(100);
    std::thread t(Run, std::move(m));
    t.join();
    return 0;
}

跟进问题:unique_ptr不可复制,只能移动。它如何与它一起工作但不适用于我的数据类型(即使我使其可移动)??