2015-04-08 2 views
-4

C++ lambdas производят std::function. Чтобы впоследствии выполнить lambda, все это состояние должно быть где-то сохранено. Итак, где хранятся эти захваченные значения и какие требования распределителя должны присутствовать для этого?Требования к памяти для C++ lambdas

Также есть ли способ изменить это поведение, если это необходимо?

+10

* «C++ Lamdas производят функцию std ::» * Нет, они этого не делают. – CoryKramer

+0

ok C++ lamdas производит что-то, что может быть назначено на std :: function – doron

ответ

3

Выражение лямбда не создает объект std::function. Вместо этого он создает объект (объект замыкания ) типа неназванного класса, называемого типом замыкания . Этот тип закрытия будет иметь следующие компоненты:

  • operator()
  • Один переменной-члена для каждого захвата копии
  • Потенциально переменные-члены для отлова по ссылке
  • Если он не имеет захватов, оператор преобразования к указателю на функцию
  • Автогенератор копирования
  • Потенциально автогенератор перемещения движется

Это гарантированно иметь:

  • конструктор Нет по умолчанию оператор присваивания
  • Нет копировать/перемещать

Ничто не гарантируется стандартом. Переменные члена типа закрытия, как и любые другие переменные-члены, имеют автоматическую продолжительность хранения; то есть они содержатся внутри самого объекта замыкания. Никаких специальных требований к распределителям нет, и нет способа изменить способ управления этими членами.

+0

Итак, как это можно присвоить функции std ::? – doron

+2

@doron ['std :: function'] (http://en.cppreference.com/w/cpp/utility/functional/function/function) имеет шаблонный конструктор, который принимает объект, реализующий' operator() '. –

+3

@doron Довольно много всего с 'operator()' присваивается 'std :: function'. Назначение 'std :: function' является свойством' std :: function', а не lambdas. – Angew

3

Lambdas - неназванный тип, который может быть сохранен в std::function. Здесь важное различие. Вы можете придумать объявление лямбда, очень похожее на объявление класса функтора. Пример:

std::vector<int> vec(......);  
auto& lambda = [vec](int x) -> void {}; 

Мы создали копию vec и получили int во время вызова в стеке. Ваша лямбда в этом случае примерно соответствует этому классу

class mylambda 
{ 
public: 
    mylambda(const std::vector& vecin) : vec(vecin) {} 
    void operator() (int x) const {} 

private: 
    std::vector<int> vec; 
}; 

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

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

2

C++ lambdas производит std::function.

Нет, они этого не делают. Они создают объект типа класса с перегруженным operator(), так что их можно вызвать как функцию.

std::function является оберткой для любого вызываемого типа, включая лямбда.

Для того чтобы иметь возможность выполнять лямбда позже, все это состояние должно быть где-то сохранено.

Действительно, зафиксированные значения необходимо хранить в лямбда.

Итак, где хранятся эти сохраненные значения и какие требования распределителя должны присутствовать для этого?

Захваченные значения сохраняются как члены класса лямбда. Ссылки на локальные переменные можно рассматривать аналогично; или может быть оптимизирован для захвата одного указателя на фрейм стека, содержащий их.

Также есть ли способ изменить это поведение, если это необходимо?

No.

1

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

где делает std::function хранит его состояния «

?.

Либо в небольшом буфере внутри std::function, либо он выделяет кусок памяти с использованием распределителя по умолчанию для хранения государство.

Хотя это в значительной степени неопределенное ли общий объект типа T будет соответствовать первому или второй категории, std::reference_wrapperявляется гарантированно использовать небольшую оптимизацию буфера; то есть следующая строка:

std::function<void()> f = std::ref(function_object); 

не содержит никакого распределения кучи.

Также есть ли способ изменить это поведение, если это необходимо?

Взгляните на the definition из std::function конструкторов: большинство из них берет дополнительный Allocator параметр, который позволяет указать пользовательский распределитель. Я предполагаю, что распределитель, если он имеет значение state, будет скопирован и стираться внутри памяти, предоставленной самим распределителем.

Смежные вопросы