Каково время жизни лямбда-выражения 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стирания типа.
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