将 std::thread 按值推入列表
Posted
技术标签:
【中文标题】将 std::thread 按值推入列表【英文标题】:Pushing std::thread by value into a list 【发布时间】:2018-10-10 14:11:04 【问题描述】:我的代码如下所示:
#include <list>
#include <thread>
void my_function(int val)
// Empty function
int main()
std::list<std::thread> threads;
for (int i = 0 ; i < 10 ; i++)
threads.push_back(std::thread(my_function, i));
return 0;
我使用threads.push_back()
的事实意味着我运行了复制构造函数std::thread::thread(const thread&)
。
安全吗?
我应该使用std::move
吗?
请假设我事先不知道我需要多少线程,所以用数组或std::vector
替换列表对我来说不是一个选项(std::vector
是一个选项前提是我提前知道线程的数量,因为我负担不起向量的realloc
操作)。
【问题讨论】:
"我使用threads.push_back()
意味着我运行了复制构造函数std::thread::thread(const thread&)
。" 这样的构造函数是delete
d,所以你不可能运行它。
为什么不使用emplace_back
?这听起来像你所追求的。 en.cppreference.com/w/cpp/container/list/emplace_back
"我应该使用 std::move" 不,临时已经是一个右值,你需要使用std::move
来转换命名变量。
@SomethingSomething std::thread(my_function, i)
是一个右值。 std::vector::push_back
有一个右值重载,它使用移动语义并且不复制。
@SomethingSomething - 差不多。它是在调用站点构造的,以便引用可以绑定到它。然后,在列表节点内,通过移动调用站点的内容来构造另一个线程。移动是安全的。只有一个句柄拥有线程。我必须支持 Slava,您应该获得一本关于 C++11 的进修书以了解术语。
【参考方案1】:
我使用 threads.push_back() 的事实意味着我运行了复制构造函数
不,它没有。由于 C++11 push_back
被重载以接受对列表值类型的右值引用。
您不能运行std::thread
的复制构造函数,因为它被声明为已删除。上面提到的push_back
重载是为了支持仅移动类型(如线程句柄)而添加的。
如果你想在不移动的情况下直接将线程初始化到容器中,那么emplace_back
可以做到这一点。但是你需要传入 std::thread
构造函数的参数,而不是从它们初始化的线程:
threads.emplace_back(my_function, i);
【讨论】:
是不是说明代码是安全的?就像我将线程直接分配给列表中的占位符一样? @SomethingSomething - 是的,就线程创建本身而言,它是安全的。标准库删除了复制构造函数,因此不安全的创建甚至不会编译。而移动构造函数做的是理智的事情。它旨在通过构造正确。以上是关于将 std::thread 按值推入列表的主要内容,如果未能解决你的问题,请参考以下文章
每次将新元素推入列表时,列表的 ReactJS 渲染时间都会增加