编译器通过引用通过堆栈指针捕获是合法的。有一个轻微的缺点(因为偏移量必须被添加到所述堆栈指针)。
在包含缺陷的当前C++标准下,您还必须通过伪指针捕获引用变量,因为绑定的生命周期必须与引用的数据一样持续,而不是直接绑定到的引用。
更简单的实现,其中每个捕获的变量对应于构造函数参数和类成员变量,具有严重的优势,即它与“更普通的”C++代码一致。需要完成一些神奇的工作this
,但除此之外,lambda闭包是一个内嵌operator()
的bog标准对象实例。 “更普通”C++代码的优化策略将起作用,错误将与“更普通”代码大部分相同,等等。
如果编译器编写者没有使用堆栈帧实现,可能引用了引用捕获在那个实现中将不能像其他编译器那样工作。当缺陷得到解决(有利于工作)时,代码将不得不再次更改。从本质上讲,使用简单实现的编译器几乎可以肯定比那些使用花式实现的编译器更少的错误和更多的工作代码。
随着堆栈帧捕获,lambda的所有优化都必须为该lambda定制。它相当于一个捕获void*
的类,对它进行指针运算,并将结果数据转换为类型指针。这将是非常难进行优化,因为指针算术往往阻止优化,尤其是堆栈变量之间的指针算术(通常是未定义的)。更糟糕的是,这样的指针算术意味着堆栈变量状态的优化(消除变量,重叠生命期,寄存器)现在必须与纠缠方式下的lambda优化相互作用。
处理这样的优化是件好事。作为奖励,因为lambda类型绑定到编译单元,所以搞乱lambda实现不会破坏编译单元之间的二进制兼容性。所以你可以相对安全地做这样的改变,一旦它们证明了稳定的改进。但是,如果您确实实施了这种优化,那么您确实会希望能够恢复到更简单的已被证明的优化。
我鼓励您为您最喜爱的开源编译器提供补丁以添加此功能。
它的实现依赖于是否存储单个指向堆栈帧的指针,或者是否存储指向每个捕获对象的指针或引用。就你而言,它似乎是后者。假设你使用的是64位平台,每个指针有7个变量* 8个字节= 56。 – Praetorian