我知道块是在栈中创建的.然而,由于我对堆栈和局部变量的知识不足,我不明白为什么我应该将块移动到堆以获得预期的结果.直观地,我觉得块代码块在堆栈中只有1个实例,这个代码引用了局部变量i 3次.如果我把它复制到堆,它将有3个不同的实例,每次它将在复制过程中捕获3个不同的值.但是我真的想更多地了解堆栈中的块代码,堆和引用局部变量.
for (int i=0; i<3; i++) b[i] = ^{ return i;}; for (int i=0; i<3; i++) printf("b %d\n",b[i]());
解决方法
范围,人.作用域.
重写为:@H_403_9@
void georgeClinton() { int (^b[3])(); // iirc // georgeClinton's scope for (int i=0; i<3; i++) { // for's scope b[i] = ^{ return i;}; } }
在每次通过()循环时,for的范围实际上是一个新的范围.但是,当然,范围在堆栈上.@H_403_9@
当您调用georgeClinton()时,您可以有效地将georgeClinton()的范围推送到堆栈上.而当georgeClinton()返回一些时髦的好处时,georgeClinton()的范围会从堆栈中弹出,将堆栈置于推动发生时的任何状态(对返回值有潜在的修改).@H_403_9@
A()循环是一样的;每次迭代将状态推送到堆栈并在迭代结束时将其弹出.@H_403_9@
因此,如果您在堆栈中存储任何东西在一个for()循环的迭代中,就像一个块,那么这个东西将在迭代结束时被销毁.要保存它,您必须将其移动到堆(您控制任何给定分配的状态的寿命).@H_403_9@
关键是块类型变量实际上是一个指针;它是对定义块的结构的引用.他们从堆栈开始,提高效率,这可能会导致像这样的微妙问题.@H_403_9@
注意一个块实际上是两件事情;它是对实现块的不可变代码的一个引用(这实际上就像一个函数指针),它是对块中捕获的数据的描述,以及如何在复制时将数据移动到堆中.@H_403_9@
也就是说,块是数据和代码的组合.代码永远不会改变.作为执行指针捕获的数据通过定义块的表达式(即块“关闭”当前的执行状态).@H_403_9@
那是跟你一起的那一点吧?当在堆栈上创建块时,它将使用插槽创建,以保存捕获的数据,也在堆栈上.@H_403_9@