C ++ 11 лямбда-реализация и модель памяти
Я хотел бы получить некоторую информацию о том, как правильно думать о замыканиях C ++ 11 иstd::function
с точки зрения того, как они реализованы и как обрабатывается память.
Хотя я не верю в преждевременную оптимизацию, у меня есть привычка тщательно обдумывать влияние моего выбора на производительность при написании нового кода. Я также занимаюсь программированием в реальном времени, например, на микроконтроллерах и для аудиосистем, где следует избегать недетерминированных пауз выделения / освобождения памяти.
Поэтому я хотел бы лучше понять, когда использовать или не использовать C ++ лямбда-выражения.
Насколько я понимаю, лямбда без захваченного замыкания в точности похожа на обратный вызов Си. Однако, когда среда захватывается либо по значению, либо по ссылке, в стеке создается анонимный объект. Когда значение-закрытие должно быть возвращено из функции, его оборачивают вstd::function
, Что происходит с закрытием памяти в этом случае? Копируется из стека в кучу? Это освобождено всякий раз, когдаstd::function
освобождается, т. е. подсчитывается ли ссылка какstd::shared_ptr
?
Я представляю, что в системе реального времени я мог бы установить цепочку лямбда-функций, передавая B в качестве аргумента продолжения A, так что конвейер обработкиA->B
создано. В этом случае замыкания A и B будут распределены один раз. Хотя я не уверен, будут ли они размещены в стеке или в куче. Однако в целом это кажется безопасным для использования в системе реального времени. С другой стороны, если B создает некоторую лямбда-функцию C, которую она возвращает, тогда память для C будет выделяться и освобождаться повторно, что было бы неприемлемо для использования в реальном времени.
В псевдокоде - цикл DSP, который, я думаю, будет безопасным в реальном времени. Я хочу выполнить обработку блока A, а затем B, где A вызывает свой аргумент. Обе эти функции возвращаютstd::function
объекты, такf
будетstd::function
объект, где его окружение хранится в куче:
auto f = A(B); // A returns a function which calls B
// Memory for the function returned by A is on the heap?
// Note that A and B may maintain a state
// via mutable value-closure!
for (t=0; t<1000; t++) {
y = f(t)
}
И тот, который я думаю, может быть плохо использовать в коде в реальном времени:
for (t=0; t<1000; t++) {
y = A(B)(t);
}
И тот, где я думаю, что стековая память, вероятно, используется для закрытия:
freq = 220;
A = 2;
for (t=0; t<1000; t++) {
y = [=](int t){ return sin(t*freq)*A; }
}
В последнем случае замыкание строится на каждой итерации цикла, но, в отличие от предыдущего примера, оно дешевое, потому что оно похоже на вызов функции, поэтому выделение кучи не производится. Кроме того, мне интересно, может ли компилятор "поднять" закрытие и внесение оптимизаций.
Это правильно? Спасибо.