Saya ingin beberapa informasi tentang bagaimana berpikir dengan benar tentang penutupan C ++ 11 dan std::function
dalam hal bagaimana mereka diimplementasikan dan bagaimana memori ditangani.
Meskipun saya tidak percaya pada pengoptimalan prematur, saya memiliki kebiasaan untuk mempertimbangkan dengan cermat dampak kinerja dari pilihan saya saat menulis kode baru. Saya juga melakukan cukup banyak pemrograman real-time, misalnya pada mikrokontroler dan untuk sistem audio, di mana jeda alokasi / deallokasi memori non-deterministik harus dihindari.
Oleh karena itu, saya ingin mengembangkan pemahaman yang lebih baik tentang kapan harus menggunakan atau tidak menggunakan C ++ lambda.
Pemahaman saya saat ini adalah bahwa lambda tanpa penutupan yang ditangkap persis seperti callback C. Namun, ketika lingkungan ditangkap baik oleh nilai atau referensi, objek anonim dibuat di tumpukan. Ketika nilai-penutupan harus dikembalikan dari fungsi, itu membungkusnya std::function
. Apa yang terjadi pada memori penutupan dalam kasus ini? Apakah itu disalin dari tumpukan ke heap? Apakah dibebaskan setiap kali std::function
dibebaskan, yaitu, apakah dihitung referensi seperti a std::shared_ptr
?
Saya membayangkan bahwa dalam sistem real-time saya dapat menyiapkan rangkaian fungsi lambda, meneruskan B sebagai argumen kelanjutan ke A, sehingga pipeline pemrosesan A->B
dibuat. Dalam hal ini, penutupan A dan B akan dialokasikan satu kali. Meskipun saya tidak yakin apakah ini akan dialokasikan di tumpukan atau heap. Namun secara umum ini tampaknya aman digunakan dalam sistem waktu nyata. Di sisi lain jika B membangun beberapa fungsi lambda C, yang dikembalikannya, maka memori untuk C akan dialokasikan dan dialokasikan berulang kali, yang tidak akan dapat diterima untuk penggunaan waktu nyata.
Dalam pseudo-code, DSP loop, yang menurut saya akan aman secara real-time. Saya ingin melakukan pemrosesan blok A dan kemudian B, di mana A menyebut argumennya. Kedua fungsi ini mengembalikan std::function
objek, jadi f
akan menjadi std::function
objek, tempat lingkungannya disimpan di heap:
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)
}
Dan yang menurut saya mungkin buruk untuk digunakan dalam kode waktu nyata:
for (t=0; t<1000; t++) {
y = A(B)(t);
}
Dan satu di mana saya pikir memori tumpukan kemungkinan digunakan untuk penutupan:
freq = 220;
A = 2;
for (t=0; t<1000; t++) {
y = [=](int t){ return sin(t*freq)*A; }
}
Dalam kasus terakhir, closure dibangun pada setiap iterasi loop, tetapi tidak seperti contoh sebelumnya, closure murah karena hanya seperti pemanggilan fungsi, tidak ada alokasi heap yang dibuat. Selain itu, saya bertanya-tanya apakah kompiler bisa "mengangkat" penutupan dan membuat optimisasi sebaris.
Apakah ini benar? Terima kasih.
operator()
. Tidak ada "pengangkatan" yang harus dilakukan, lambda bukanlah sesuatu yang istimewa. Mereka hanyalah kependekan dari objek fungsi lokal.