Каково время жизни лямбда-выражения C++?



(Я читал, что такое время жизни лямбда-производных неявных функторов в C++? уже и он не отвечает на этот вопрос.)



Я понимаю, что синтаксис лямбда-кода C++ - это просто сахар для создания экземпляра анонимного класса с оператором вызова и некоторым состоянием, и я понимаю требования к жизни этого состояния (решается ли вы захватить значение по ссылке.) Но каково время жизни самого лямбда-объекта? В следующем примере это std::function возвращенный экземпляр будет полезен?



std::function<int(int)> meta_add(int x) {
auto add = [x](int y) { return x + y; };
return add;
}


если это как это работает? Это кажется мне слишком много магии - я могу только представить, что это работает std::function копирование всего моего экземпляра, который может быть очень тяжелым в зависимости от того, что я захватил - в прошлом я использовал std::function в основном с голыми указателями функций, и копирование их происходит быстро. Это также кажется проблематичным в свете std::functionстирания типа.

583   4  

4 ответов:

время жизни-это именно то, что было бы, если бы вы заменили свою лямбду на ручной функтор:

struct lambda {
   lambda(int x) : x(x) { }
   int operator ()(int y) { return x + y; }

private:
   int x;
};

std::function<int(int)> meta_add(int x) {
   lambda add(x);
   return add;
}

объект будет создан, локальный для meta_add функция, затем перемещается [во всей своей полноте, включая значение x] в возвращаемое значение, то локальный экземпляр выйдет из области видимости и уничтожается, как обычно. Но объект, возвращенный из функции, будет оставаться действительным до тех пор, пока std::function объект, который держит его тут. Как долго это очевидно зависит от контекста вызова.

кажется, вы больше смущены std::function чем лямбды.

std::function использует метод, называемый стиранием типа. А вот и быстрый полет.

class Base
{
  virtual ~Base() {}
  virtual int call( float ) =0;
};

template< typename T>
class Eraser : public Base
{
public:
   Eraser( T t ) : m_t(t) { }
   virtual int call( float f ) override { return m_t(f); }
private:
   T m_t;
};

class Erased
{
public:
   template<typename T>
   Erased( T t ) : m_erased( new Eraser<T>(t) ) { }

   int do_call( float f )
   {
      return m_erased->call( f );
   }
private:
   Base* m_erased;
};

почему вы хотите стереть тип? Это не тот тип, который мы хотим просто int (*)(float)?

что тип стирания позволяет Erased теперь можно хранить любое значение, которое вызывается как int(float).

int boring( float f);
short interesting( double d );
struct Powerful
{
   int operator() ( float );
};

Erased e_boring( &boring );
Erased e_interesting( &interesting );
Erased e_powerful( Powerful() );
Erased e_useful( []( float f ) { return 42; } );

Это:

[x](int y) { return x + y; };

эквивалентно: (или может рассматриваться тоже)

struct MyLambda
{
    MyLambda(int x): x(x) {}
    int operator()(int y) const { return x + y; }
private:
    int x;
};

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

в коде, который вы выложили:

std::function<int(int)> meta_add(int x) {
    auto add = [x](int y) { return x + y; };
    return add;
}

The std::function<int(int)> объект, возвращаемый функцией, фактически содержит перемещенный экземпляр объекта лямбда-функции, который был назначен локальной переменной add.

при определении лямбды C++11, которая захватывает по значению или по ссылке, компилятор C++ автоматически создает уникальный функциональный тип, экземпляр которого создается, когда лямбда вызывается или назначается переменной. К примеру, на C++ компилятор может создать следующий тип класса для лямбда-выражения, определенного [x](int y) { return x + y; }:

class __lambda_373s27a
{
    int x;

public:
    __lambda_373s27a(int x_)
        : x(x_)
    {
    }

    int operator()(int y) const {
        return x + y;
    }
};

затем meta_add функция по существу эквивалентна:

std::function<int(int)> meta_add(int x) {
    __lambda_373s27a add = __lambda_373s27a(x);
    return add;
}

EDIT: кстати, я не уверен, что вы это знаете, но это пример функции карринг в C++11.

Comments

    Ничего не найдено.