Почему аргументы перемещались дважды при построении std::thread

avatar
Shaoyan
5 января 2020 в 16:24
137
2
6

Рассмотрите эту программу, которая фактически создает std::thread, которая вызывает функцию func() с arg в качестве аргумента:

#include <thread>
#include <iostream>

struct foo {
   foo() = default;
   foo(const foo&) { std::cout << "copy ctor" << std::endl; }
   foo(foo&&) noexcept { std::cout << "move ctor" << std::endl; }
};

void func(foo){}

int main() {
   foo arg;
   std::thread th(func, arg);
   th.join();
}

Мой вывод

copy ctor
move ctor
move ctor

Насколько я понимаю, arg копируется внутри объекта потока, а затем передается func() как rvalue (перемещено). Итак, я ожидаю конструкцию с одним копированием и конструкцию с одним перемещением.

Почему существует конструкция второго хода?

Источник
Rakete1111
5 января 2020 в 16:37
2

Связанный бит: coderhelper.com/questions/50362849/…

Lightness Races in Orbit
5 января 2020 в 16:42
2

А, на самом деле дурак. Позор, он не может быть закрыт как таковой из-за отсутствия ответов (потому что nm по какой-то причине написал свой ответ в разделе комментариев)

Ответы (2)

avatar
bipll
5 января 2020 в 17:32
3

Вы передаете аргумент func по значению, которое должно составлять второй ход. По-видимому, std::thread сохраняет его внутри еще раз, прежде чем вызывать func, что, насколько мне известно, является абсолютно законным с точки зрения Стандарта.

avatar
Jonathan Wakely
5 февраля 2020 в 14:04
1

Итак, я ожидаю одну конструкцию копирования и одну конструкцию перемещения.

Стандарт на самом деле этого не говорит. Реализации разрешено выполнять дополнительные внутренние конструкции перемещения.

Однако это потенциально менее эффективно. Это было https://gcc.gnu.org/PR69724 и было исправлено в предстоящем выпуске GCC 10.