Захват общих вызываемых объектов во вложенных лямбдах — всегда вперед?

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

template <typename TF>
void interface(TF&& f)
{
nested0([/*...*/]()
{
nested1([/*...*/](auto& x)
{
nested2([&x, /*...*/]()
{
f(x);
});
});
});
}

Обратите внимание, что interface принимает вызываемый объект типа TF перенаправив ссылку (ранее известный как универсальная ссылка). Вызываемый объект — это обычно лямбда с различными захваченными переменными, как по значению, так и по ссылке.

Каков наилучший (с точки зрения производительности) способ захвата f во вложенных лямбдах при сохранении правильности?

Я могу придумать три варианта:

  1. Захватить f по копии.

    nested0([f]()
    {
    nested1([f](auto& x)
    {
    nested2([&x, f]()
    {
    f(x);
    });
    });
    });
    

    Может вызвать ненужные копии, и если захваченный объект mutable это может вызвать неправильное поведение.

  2. Захватить f по ссылке.

    nested0([&f]()
    {
    nested1([&f](auto& x)
    {
    nested2([&x, &f]()
    {
    f(x);
    });
    });
    });
    

    Кажется разумным, но может вызвать проблемы, если какая-либо из вложенных лямбд выполняет действие, которое переживает владельца f, Представь если nested2тело было выполнено в отдельном потоке — f уже может быть вне области.

  3. Сделать лямбды mutable и захватить совершенной пересылкой.

    #define FWD(...) std::forward<decltype(__VA_ARGS__)>(__VA_ARGS__)
    
    nested0([f = FWD(f)]() mutable
    {
    nested1([f = FWD(f)](auto& x) mutable
    {
    nested2([&x, f = FWD(f)]() mutable
    {
    f(x);
    });
    });
    });
    

    Лямбды должны быть mutable потому что мы потенциально движемся f из лямбды в другую. Этот подход, по-видимому, позволяет избежать ненужных копий и правильно перемещать вызываемый объект, если он должен пережить первоначальный вызывающий объект.

Вариант 3 всегда лучший или у него есть потенциальный недостаток? …или, может быть, нет «лучшего и правильного» способа вообще (знание об вызываемом объекте обязательно)?

2

Решение

Как упоминалось в комментариях, трудно сказать с таким плохим контекстом, данным о проблеме.
Тем не менее, мне кажется, что лучшим решением будет захватить все по ссылке и нарушать эту логику всякий раз, когда вам нужна копия, цель которой — пережить время жизни f, В качестве примера:

nested0([&f]() {
n1([&f](auto& x) {
n2([&x,
// get a local copy of f
f{std::forward<TF>(f)}]() {
f(x);
});
});
});

Во всяком случае, для такой проблемы не существует практического правила.
Лучший Решение тесно связано с реальной проблемой.
По-прежнему. Справедливо.

1

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]