为什么在块被复制之前,__blockvariables被移动到堆上?

我知道,一个__blockvariables将被移动到堆栈中,如果一个块访问它被复制。 但是下面的testing代码告诉我,在块的复制之前__blockvariables被移到了堆上。

也就是说,这四个输出是:stack => heap => heap => heap,这不是我预期的结果:stack => stack => stack => heap。

有人能把我整理出来吗?

 __block int x = 0; int *pointerToX = &x; //1. It's on the stack NSLog(@"x's location is on the stack: %p", &x); int (^block)() = ^{ x += 1; return x; }; //2. I think its stack, but it's heap NSLog(@"x's location is on the %@: %p", (&x == pointerToX ? @"stack" : @"heap"), &x); //it's heap not stack block(); //3. I think its stack, but it's heap NSLog(@"x's location is on the %@: %p", (&x == pointerToX ? @"stack" : @"heap"), &x); //it's heap not stack block = [block copy]; // The variable x will be moved to the heap //4. I think its stack, but it's heap NSLog(@"x's location is on the %@: %p", (&x == pointerToX ? @"stack" : @"heap"), &x); //heap 

让我先说这个:块很奇怪。

现在,当你开始时,你已经声明了一个variablesx,并且用__block作为前缀。 无论如何, __block是什么? 那么,对于在块的词法范围中捕获的对象,variables将被保留以保证它们在执行时位于附近。 但是对于原始variables,块通过强制它们被const值传递而不是通过引用来保证它们的值。 通过预先设定__block ,您可以让编译器自由统治,以便在复制块时将variables从堆栈中“神奇”地移动到堆中。 清楚的是, __blockvariables实际上是堆栈分配的,但是当块被复制时,它们被移动到堆( malloc() 'd)。

但是,x的位置奇怪的变化呢? 那么再回到__block 。 因为你没有像普通variables那样使用x的const引用,所以blocks会使用一个(稍微恼人的)技巧:一个block创build一个指向任何__blockvariables的指针,如果这个variables被突变,它将被解除引用。 达达! 你的variables没有从堆栈移动到堆,块只是取消指向它的指针并将其移动到内存中!

所以,真的,你对你的variables何时何地被移动感到困惑。 你的例子正在logging正确的值。

您的预期输出是基于您假设该块未被复制直到步骤3-4。 然而,在块规范中没有任何保证的情况。

是的,当你显式调用-copy时,块将被复制。 但为什么不能早些复制呢? 先前复制块是永远不会错的 。 因此,当一个块被复制时是不确定的,你不应该依赖它。

ARC下编译器的一些最新版本可能比较保守,在创build后立即复制一个块。 没有什么不妥。 同样,如果是这样,那将是一个实现细节,其他编译器或未来版本可能会做一些不同的事情。

我用ARC在Objective-C中提出了同样的问题, 当我定义一个块时,编译器做了什么?

在ARC中运行代码的情况

在ARC中,

可保留对象所有者types的块variables通过从堆栈副本移动的结果初始化堆副本而移出堆栈。

http://clang.llvm.org/docs/AutomaticReferenceCounting.html#blocks中

Interesting Posts