Совершенная пересылка const ref ошибка удержания - PullRequest
0 голосов
/ 14 февраля 2019

Я написал супер простую оболочку потока, которая берет функцию и запускает ее в потоке, а также предоставляет простой механизм, чтобы сигнализировать потоку, когда пора выходить.Функция запуска выглядит следующим образом:

//tw.hpp

class ThreadWrapper
{
public:
  // ...snipped ...
  template<typename... Args>
  bool start(Args&& ... args)
  {
    ft_ = std::async(std::launch::async, std::forward<Args>(args)...  );
    return true;
  }
};

Когда я использую ее для функции, не являющейся членом, мне нужно передать const ref обертки в функцию, которая выполняется, чтобы предоставить дескриптор, который может использовать функциячтобы знать, когда выйти:

void lone_worker(const ThreadWrapper& tw)
{
  while (!tw.is_quit_requested())
  {
    std::cout << "working hard alone\n";
    sleep(1);
  }
}

void nonmember_demo()
{
  ThreadWrapper tw;
  tw.start(&lone_worker, std::cref(tw)); // the cref is need to avoid hundreds of lines of compiler template puke with no useful error messages
  sleep(5);
  std::cout << "quitting\n";
  tw.request_quit();
}

Я был застигнут врасплох, когда я изначально скомпилировал его без использования std::cref, буквально сотнями строк puke шаблона компилятора (gcc 8.1.0) и без явной причины.Есть ли что-то, что я не сделал правильно с идеальной пересылкой, чтобы потребовать использования cref?Я предполагаю, что это частично вызвано тем, что класс не подлежит копированию (он содержит std :: future), что немного пахнет, так как, по крайней мере, я предполагаю, что в первую очередь не следует делать копию.Полный пример здесь: https://coliru.stacked -crooked.com / a / 0eb4d6160b44764a

1 Ответ

0 голосов
/ 14 февраля 2019

, который немного пахнет, так как, по крайней мере, я предполагаю, что в первую очередь не следует делать копию

Вы ошибаетесь.async в основном просто пересылается на thread, который начинается с выполнения:

std::invoke(decay_copy(std::forward<Function>(f)), 
            decay_copy(std::forward<Args>(args))...);

Это копирует все аргументы.Смысл справочной оболочки - избежать этой копии - вместо копирования объекта ThreadWrapper (который не может быть скопирован), вы копируете std::reference_wrapper<ThreadWrapper const> (который можно копировать).

Со связанной страницы cppreference для thread:

Аргументы функции потока перемещаются или копируются по значению.Если в функцию потока необходимо передать ссылочный аргумент, его необходимо обернуть (например, с помощью std::ref или std::cref).

...