C ++ 11 kapanışlarının nasıl doğru bir şekilde düşünülebileceği std::function
ve nasıl uygulandığı ve belleğin nasıl işlendiği konusunda biraz bilgi almak istiyorum .
Erken optimizasyona inanmasam da, yeni kod yazarken seçimlerimin performansa etkisini dikkatlice düşünme alışkanlığım var. Ayrıca, mikrodenetleyicilerde ve deterministik olmayan bellek tahsisi / serbest bırakma duraklamalarının önleneceği ses sistemleri için makul miktarda gerçek zamanlı programlama yapıyorum.
Bu nedenle, C ++ lambdaları ne zaman kullanıp kullanmama konusunda daha iyi bir anlayış geliştirmek istiyorum.
Şu anki anlayışım, yakalanan kapanışı olmayan bir lambda'nın tam olarak bir C geri araması gibi olduğudur. Bununla birlikte, ortam değere göre veya referans olarak yakalandığında, yığın üzerinde anonim bir nesne oluşturulur. Bir işlevden bir değer kapanışı döndürülmesi gerektiğinde, onu içine alır std::function
. Bu durumda kapanış hafızasına ne olur? Yığından yığına kopyalanıyor mu? Ne zaman serbest std::function
bırakılırsa, yani a gibi referans sayılır std::shared_ptr
mı?
Gerçek zamanlı bir sistemde, B'yi devam argümanı olarak A'ya geçirerek bir lambda işlevleri zinciri kurabileceğimi ve böylece bir işlem hattının A->B
yaratılacağını hayal ediyorum . Bu durumda, A ve B kapanışları bir kez tahsis edilecektir. Bunların yığına mı yoksa yığına mı tahsis edileceğinden emin değilim. Ancak genel olarak bu, gerçek zamanlı bir sistemde kullanmak için güvenli görünmektedir. Öte yandan, eğer B, döndürdüğü bazı lambda C fonksiyonunu inşa ederse, o zaman C için bellek tekrar tekrar tahsis edilir ve serbest bırakılır, bu da gerçek zamanlı kullanım için kabul edilemez.
Sözde kodda, gerçek zamanlı güvenli olacağını düşündüğüm bir DSP döngüsü. A bloğunu ve ardından A'nın argümanını çağırdığı B bloğunu gerçekleştirmek istiyorum. Bu işlevlerin her ikisi de std::function
nesneleri döndürür , dolayısıyla ortamının öbek üzerinde depolandığı f
bir std::function
nesne olacaktır :
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)
}
Ve gerçek zamanlı kodda kullanmanın kötü olabileceğini düşündüğüm bir şey:
for (t=0; t<1000; t++) {
y = A(B)(t);
}
Ve yığın hafızasının muhtemelen kapanış için kullanıldığını düşündüğüm yer:
freq = 220;
A = 2;
for (t=0; t<1000; t++) {
y = [=](int t){ return sin(t*freq)*A; }
}
İkinci durumda, kapanma döngünün her yinelemesinde oluşturulur, ancak önceki örnekten farklı olarak ucuzdur, çünkü bu sadece bir işlev çağrısı gibidir, yığın tahsisleri yapılmaz. Dahası, bir derleyicinin kapanışı "kaldırıp kaldırmayacağını" ve satır içi optimizasyonlar yapıp yapamayacağını merak ediyorum.
Bu doğru mu? Teşekkür ederim.
operator()
. Yapılması gereken bir "kaldırma" yoktur, lambdalar özel bir şey değildir. Yerel bir işlev nesnesi için sadece kısa bir eldir.