Передача изменчивой лямбды с unique_ptr в const & std :: function - PullRequest
0 голосов
/ 26 октября 2018

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

void dispatch(const std::function<void()>& fn) {
    fn();
}

Мне нужно загрузить новый объект в новом потоке, не прерывая основной поток. Поэтому я делаю следующее: 1) запускаю новый поток и создаю новый уникальный указатель внутри потока, 2) вызываю dispatch и распространяю новый уникальный указатель там, где он принадлежит.

std::unique_ptr<std::string> foo; // nullptr

// do the loading in a new thread:
std::thread t([&](){
    // in the new thread, load new value "Blah" and store it temporarily
    auto bar = std::make_unique<std::string>("Blah");
    dispatch([bar2 = std::move(bar), &foo]() mutable {
        foo = std::move(bar2); // propagate the loaded value to foo
    });
});
t.join(); // for the sake of this example

std::cout << "foo = " << *foo << std::endl; // this should say: foo = Blah

Запустить пример онлайн: http://cpp.sh/5zjvm

Этот код не компилируется, потому что внутренняя лямбда в dispatch равна mutable и поэтому не вписывается в dispatch(const std::function<void()>& fn), для которого требуется const&.

Однако лямбда должна быть mutable, потому что она должна вызывать std::move для уникальных указателей.

Этот код можно исправить, например, изменив dispatch на:

template <typename Fn>
void dispatch(Fn fn) {
    fn();
}

К сожалению, функция dispatch является API библиотеки, и я не могу ее изменить.

Есть ли выход из этой проблемы без избавления от уникальных указателей?

1 Ответ

0 голосов
/ 26 октября 2018

Нет, это не ваша проблема.

Ваша проблема в том, что ваша лямбда не может быть скопирована, так как в ней есть уникальный ptr, захваченный по значению.

std::function<Sig> тип стирает до

  1. Вызов с Sig

  2. Уничтожить

  3. Копирование (и иногда перемещение)

  4. Чугунная спина к первоначальному типа

Ваша лямбда не может быть скопирована, поэтому не может быть сохранена в std::function.

Решение для ленивого кодера:

    dispatch([bar2 = std::make_shared<decltype(bar)>(std::move(bar)), &foo]() mutable {
        foo = std::move(*bar2);
    });

, где мы помещаем состояние без копирования в shared_ptr.

...