1

我正在阅读有关 c++11 多线程的文档,并在std::thread.

代码:

void thread_task(int n) {
  ...
}

int main(int argc, const char *argv[])
{
    std::thread threads[5];
    for (int i = 0; i < 5; i++) {
        threads[i] = std::thread(thread_task, i + 1);
    }

    return 0;
}

我不明白threads[i] = std::thread(thread_task, i + 1);。是std::thread静态函数调用,并返回 std::thread 对象的引用吗?听起来不可思议,但似乎是代码所说的。

因为我会这样写:

std::thread *threads[5];
for (int i = 0; i < 5; i++) {
    threads[i] = new std::thread(thread_task, i + 1);
}

谢谢。

4

4 回答 4

13

让我们来看看到底发生了什么:

std::thread threads[5];

这将创建一个包含 5 个对象的数组std::thread,这些对象是默认构造的。目前它们代表“不是线程”,因为这是状态默认构造将它们留在其中。

for (int i = 0; i < 5; i++) {
    threads[i] = std::thread(thread_task, i + 1);
}

这使用 的移动形式operator=。因为线程是不可复制的,只有可移动的,thread& operator=(thread&& t)被定义而thread& operator=(const thread& t)不是。这会将线程对象分配给threads[i]新构造的std::thread(thread_task, i + 1);.

这里没有理由使用指针数组。它只会增加内存泄漏的可能性。

于 2013-09-07T12:10:24.843 回答
2

这个:

std::thread(thread_task, i + 1)

是对 std::thread 构造函数的调用,它创建一个新的线程对象并将其传递给 thread_task 函数的指针,该函数本身以 i+1 作为参数调用。

该赋值是一个移动赋值(因为右手边指的是一个匿名对象),而不是一个复制赋值。请注意,std::thread 复制构造函数和复制赋值运算符被删除。

这实际上是比使用指针更干净的方法,因为当线程数组超出范围时,std::thread 对象将被自动销毁。

于 2013-09-07T12:10:10.623 回答
2

std::thread静态函数调用,并返回std::thread对象的引用吗?

不,它正在创建一个临时线程对象;就像int(42)创建一个临时整数一样。分配将其移动到数组中,因为线程是可移动的,并且可以从中移动临时对象。

因为我会这样写:

您无缘无故地引入了动态分配、额外的间接级别和内存泄漏(除非您还添加代码以在完成时删除它们)。

于 2013-09-07T12:06:18.240 回答
2

默认构造函数std::thread创建一个不代表线程的实例。该分配是一个move-assignment,因为也不允许复制。它将由创建的真实实例移动std::thread(thread_task, i + 1);到数组中。

于 2013-09-07T12:06:47.907 回答