我想了解一些关于如何正确地考虑 C + + 11闭包和 std::function
的信息,包括它们是如何实现的以及如何处理内存的。
虽然我不相信过早的优化,但我有一个习惯,就是在编写新代码时,会仔细考虑我的选择对性能的影响。我还做了相当多的实时编程,例如在微控制器和音频系统上,这样可以避免不确定的内存分配/释放暂停。
因此,我想更好地理解何时使用或不使用 C + + lambdas。
我目前的理解是,没有捕获闭包的 lambda 与 C 回调完全一样。但是,当通过值或引用捕获环境时,将在堆栈上创建一个匿名对象。如果必须从函数返回值闭包,则将其包装在 std::function
中。在这种情况下,闭包内存发生了什么变化?它是否从堆栈复制到堆中?它是否在 std::function
被释放的时候被释放,也就是说,它是否像 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; }
}
在后一种情况下,闭包是在循环的每次迭代中构造的,但是与前一个示例不同,它的成本很低,因为它就像一个函数调用,没有进行堆分配。此外,我想知道编译器是否可以“提升”闭包并进行内联优化。
是这样吗? 谢谢。