具有对象右值引用的线程
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不可复制,只能移动。它如何与它一起工作但不适用于我的数据类型(即使我使其可移动)??
我有一个接受对象右值引用的函数,我想 运行 在 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不可复制,只能移动。它如何与它一起工作但不适用于我的数据类型(即使我使其可移动)??