Не используйте захватывающие лямбда-выражения, которые являются корутинами
Причина
Паттерны использования, которые корректны с нормальными лямбда-выражениями, опасны с лямбда-выражениями корутин. Очевидный паттерн захвата переменных приведет к доступу к освобожденной памяти после первой точки приостановки, даже для подсчитываемых по ссылке интеллектуальных указателей и копируемых типов.
Лямбда-выражение приводит к объекту замыкания с хранилищем, часто в стеке, который в какой-то момент выйдет из области видимости. Когда объект замыкания выходит из области видимости, захватываемые переменные также выходят из области видимости. Обычные лямбда-выражения завершат выполнение к этому времени, поэтому это не проблема. Лямбда-выражения корутин могут возобновиться после приостановки после того, как объект замыкания был уничтожен, и в этот момент все захватываемые переменные будут доступом к освобожденной памяти.
Плохой пример
int value = get_value();
std::shared_ptr<Foo> sharedFoo = get_foo();
{
const auto lambda = [value, sharedFoo]() -> std::future<void>
{
co_await something();
// "sharedFoo" и "value" уже были уничтожены
// "shared" указатель ничего не добился
};
lambda();
} // объект замыкания лямбда-выражения теперь вышел из области видимости
Лучший пример
int value = get_value();
std::shared_ptr<Foo> sharedFoo = get_foo();
{
// принять в качестве параметра по значению вместо захвата
const auto lambda = [](auto sharedFoo, auto value) -> std::future<void>
{
co_await something();
// sharedFoo и value все еще действительны в этой точке
};
lambda(sharedFoo, value);
} // объект замыкания лямбда-выражения теперь вышел из области видимости
Наилучший пример
Используйте функцию для корутин.
std::future<void> Class::do_something(int value, std::shared_ptr<Foo> sharedFoo)
{
co_await something();
// sharedFoo и value все еще действительны в этой точке
}
void SomeOtherFunction()
{
int value = get_value();
std::shared_ptr<Foo> sharedFoo = get_foo();
do_something(value, sharedFoo);
}
Применение
Отметьте лямбда-выражение, которое является корутиной и имеет непустой список захватываемых переменных.