C ++ 11 lambda实现和内存模型

我想了解一些关于如何正确思考C ++ 11闭包和std::function的信息,以及它们如何实现以及如何处理内存。

尽pipe我不相信过早的优化,但是在编写新代码的时候,我确实有习惯认真考虑我的select对性能的影响。 我也做了相当数量的实时编程,例如在微控制器和audio系统上,要避免非确定性内存分配/释放暂停。

因此,我想更好地了解何时使用或不使用C ++ lambdaexpression式。

我目前的理解是,没有捕获闭包的lambda完全像Ccallback。 但是,当通过值或引用捕获环境时,会在堆栈上创build一个匿名对象。 当一个函数必须返回一个值闭包时,它会把它包装在std::function 。 在这种情况下closures内存会发生什么? 它是从堆栈复制到堆? 每当std::function被释放时它是否被释放,也就是说,它是否像std::shared_ptr一样被引用计数?

我想在一个实时系统中,我可以设置一个lambda函数链,将B作为延续parameter passing给A,以便创build一个处理pipe道A->B 在这种情况下,A和Bclosures将被分配一次。 虽然我不确定这些是否会被分配在堆栈或堆上。 但是总的来说,这在实时系统中似乎是安全的。 另一方面,如果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); } 

还有一个我认为堆栈内存可能用于closures的地方:

 freq = 220; A = 2; for (t=0; t<1000; t++) { y = [=](int t){ return sin(t*freq)*A; } } 

在后一种情况下,闭包是在循环的每次迭代中构造的,但与前面的示例不同,它是便宜的,因为它就像函数调用一样,不会进行堆分配。 此外,我想知道一个编译器是否可以“解除”闭包并进行优化。

它是否正确? 谢谢。

我目前的理解是,没有捕获闭包的lambda完全像Ccallback。 但是,当通过值或引用捕获环境时,会在堆栈上创build一个匿名对象。

没有; 它始终是一个未知types的C ++对象,在堆栈​​上创build。 一个无捕获的lambda可以被转换成函数指针(尽pipe它是否适合C调用约定是依赖于实现的),但这并不意味着它一个函数指针。

当一个函数必须返回一个值闭包时,它会把它包装在std :: function中。 在这种情况下closures内存会发生什么?

lambda在C ++ 11中没有什么特别之处。 这是一个像任何其他对象的对象。 lambdaexpression式产生一个临时的,可以用来初始化堆栈上的一个variables:

 auto lamb = []() {return 5;}; 

lamb是一个堆栈对象。 它有一个构造函数和析构函数。 它将遵循所有的C ++规则。 lamb的types将包含捕获的值/参考; 它们将成为该对象的成员,就像任何其他types的其他对象成员一样。

你可以把它给一个std::function

 auto func_lamb = std::function<int()>(lamb); 

在这种情况下,它会得到一个lamb价值的副本 。 如果lamb有价值地捕获了任何东西,就会有两个这样的价值; 一个在lamb ,一个在func_lamb

当前范围结束时, func_lamb清理栈variables的规则, func_lamb将被销毁,接着是func_lamb

你可以很容易地在堆上分配一个:

 auto func_lamb_ptr = new std::function<int()>(lamb); 

std::function内容的内存究竟在哪里取决于实现,但std::function使用的types擦除通常至less需要一个内存分配。 这就是为什么std::function的构造函数可以使用分配器。

每当std :: function被释放时它是否被释放,也就是说,它是否像std :: shared_ptr一样被引用计数?

std::function存储其内容的副本 。 与几乎所有标准库C ++types一样, function使用值语义 。 因此,它是可复制的; 当它被复制时,新的function对象是完全分离的。 它也是可移动的,所以任何内部分配都可以适当地转移,而不需要更多的分配和复制。

因此不需要参考计数。

假设“内存分配”等同于“在实时代码中使用不好”,其他所有内容都是正确的。