我想要一些关于如何正确思考 C++11 闭包以及std::function
如何实现它们以及如何处理内存的信息。
虽然我不相信过早的优化,但我确实有一个习惯,即在编写新代码时仔细考虑我的选择对性能的影响。我还进行了大量的实时编程,例如在微控制器和音频系统上,要避免非确定性的内存分配/释放暂停。
因此,我想更好地了解何时使用或不使用 C++ lambda。
我目前的理解是,没有捕获闭包的 lambda 与 C 回调完全一样。但是,当通过值或引用捕获环境时,会在堆栈上创建一个匿名对象。当必须从函数返回值闭包时,将其包装在std::function
. 在这种情况下,闭包内存会发生什么?它是从堆栈复制到堆的吗?是否在释放时std::function
释放它,即它是否像 a 一样被引用计数std::shared_ptr
?
我想在一个实时系统中,我可以设置一个 lambda 函数链,将 B 作为一个延续参数传递给 A,从而A->B
创建一个处理管道。在这种情况下,A 和 B 闭包将被分配一次。虽然我不确定这些是否会分配在堆栈或堆上。然而,一般来说,这在实时系统中使用似乎是安全的。另一方面,如果 B 构造了一些它返回的 lambda 函数 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; }
}
在后一种情况下,闭包是在循环的每次迭代中构造的,但与前面的示例不同,它很便宜,因为它就像一个函数调用,不进行堆分配。此外,我想知道编译器是否可以“解除”闭包并进行内联优化。
它是否正确?谢谢你。