Мне хотелось бы получить некоторую информацию о том, как правильно думать о замыканиях std::function
в C ++ 11, о том, как они реализованы и как обрабатывается память.
Хотя я не верю в преждевременную оптимизацию, у меня есть привычка тщательно учитывать влияние моего выбора на производительность при написании нового кода. Я также занимаюсь программированием в реальном времени, например, на микроконтроллерах и для аудиосистем, где следует избегать недетерминированных пауз при выделении / освобождении памяти.
Поэтому я хотел бы лучше понять, когда использовать или не использовать лямбды C ++.
В настоящее время я понимаю, что лямбда без захваченного замыкания в точности похожа на обратный вызов C. Однако, когда среда захватывается либо по значению, либо по ссылке, в стеке создается анонимный объект. Когда значение-закрытие должно быть возвращено из функции, его оборачивают std::function
. Что в этом случае происходит с закрытием памяти? Копируется из стека в кучу? Освобождается ли он всякий раз, когда std::function
освобождается объект, т. Е. Подсчитывается ли он как a 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; }
}
В последнем случае замыкание создается на каждой итерации цикла, но, в отличие от предыдущего примера, это дешево, потому что это похоже на вызов функции, не выделяется куча. Более того, мне интересно, может ли компилятор "снять" закрытие и произвести оптимизацию встраивания.
Это правильно? Спасибо.
operator()
. Никакого "подъема" делать не надо, лямбды - это не что иное, как. Это просто сокращение от локального функционального объекта.