将 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&amp;)

安全吗?

我应该使用std::move 吗?

请假设我事先不知道我需要多少线程,所以用数组或std::vector 替换列表对我来说不是一个选项(std::vector 是一个选项前提是我提前知道线程的数量,因为我负担不起向量的realloc 操作)。

【问题讨论】:

"我使用threads.push_back()意味着我运行了复制构造函数std::thread::thread(const thread&amp;)" 这样的构造函数是deleted,所以你不可能运行它。 为什么不使用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 渲染时间都会增加

无法将派生类 push_back() 推入 C++ 中的 STL 列表

按值属性定位列表项

Redis列表操作

如何按值而不是按引用将数组添加到列表中?

按值传递列表以发挥作用