块和堆栈

发布于 2024-11-10 04:19:37 字数 352 浏览 0 评论 0原文

我知道块是在堆栈中创建的。然而,由于我对堆栈和局部变量没有足够的了解,我无法理解为什么我应该将块移动到堆以获得预期的结果。直觉上我觉得块代码块在堆栈中只有 1 个实例,这段代码引用了局部变量 i 3 次。如果我将其复制到堆,它将有 3 个不同的实例,并且每次在复制过程中都会捕获 3 个不同的 i 值。但我真的很想了解更多有关堆栈、堆中的块代码和引用局部变量的信息。

for (int i=0; i<3; i++)
    b[i] = ^{ return i;};
for (int i=0; i<3; i++)
    printf("b %d\n", b[i]());

I know that blocks are created in the stack. However, since I don't have enough knowledge about stack and local variables, I can not understand why I should move the block to heap in order to have expected result. Intuitively I feel like the block code chunk has only 1 instance in the stack, this code is referencing to local variable i 3 times. If I copy it to heap it will have 3 different instances and each time it will capture 3 different values of i during copy procedure. But I would really like to know more about block code in stack, heap and referencing local variables.

for (int i=0; i<3; i++)
    b[i] = ^{ return i;};
for (int i=0; i<3; i++)
    printf("b %d\n", b[i]());

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

晨光如昨 2024-11-17 04:19:37

范围,伙计。范围。

将其重写为:

void georgeClinton() {
    int (^b[3])(); // iirc
    // georgeClinton's scope
    for (int i=0; i<3; i++) {
        // for's scope
        b[i] = ^{ return i;};
    }
}

在每次通过 for() 循环时,for 的作用域实际上是一个新的作用域。但是,当然,范围是在堆栈上的。

当您调用georgeClinton() 时,您实际上将georgeClinton() 的作用域到堆栈上。当 georgeClinton() 带着一些时髦的好处返回时,georgeClinton() 的作用域会从堆栈中弹出,使堆栈处于推送发生时的任何状态(可能会修改返回值)。

for() 循环是同样的事情;每次迭代都会将状态推入堆栈并在迭代结束时将其弹出。

因此,如果您在 for() 循环的迭代中将任何内容(例如块)存储在堆栈上,那么该内容将在迭代结束时被销毁。要保留它,您必须将其移动到堆(您可以在堆中控制任何给定分配的状态的生命周期)。

关键是块类型变量实际上是一个指针;它是对定义块的结构的引用。他们从堆栈开始是为了提高效率,这可能会导致像这样的微妙问题。

请注意,块实际上是两件事;它是对实现该块的不可变代码位的引用(实际上就像一个函数指针),它是对块中捕获的数据以及如何处理该数据的描述。复制时移至堆。

也就是说,块是数据和代码的组合。永不改变的代码。当执行指针经过定义块的表达式时捕获的数据(即块“关闭”当前的执行状态)。

正是后一点让你绊倒。当在堆栈上创建块时,它会创建一个槽来保存捕获的数据,也在堆栈上。

Scopes, man. Scopes.

Rewrite that as:

void georgeClinton() {
    int (^b[3])(); // iirc
    // georgeClinton's scope
    for (int i=0; i<3; i++) {
        // for's scope
        b[i] = ^{ return i;};
    }
}

On every pass through that for() loop, for's scope is effectively a new scope. But, of course, scopes are on the stack.

When you call georgeClinton(), you effectively push georgeClinton()'s scope onto the stack. And when georgeClinton() returns with some funky goodness, georgeClinton()'s scope is popped off the stack, leaving the stack in whatever state it was in when the push happened (with a potential modification for the return value).

A for() loop is the same thing; each iteration pushes state onto the stack and pops it off at the end of the iteration.

Thus, if you store anything on the stack in an iteration of a for() loop, like a block, that thing will be destroyed at the end of the iteration. To preserve it, you must move it to the heap (where you control the lifespan of the state of any given allocation).

The key being that a block typed variable is really a pointer; it is a reference to a structure that defines the block. They start on the stack for efficiency and this can lead to subtle issues like this one.

Note that a block is really two things; it is a reference to the bit of immutable code that implements the block (which is really just like a function pointer) and it is a description of the data captured in the block and how that data is to be moved to the heap when copied.

That is, a block is the combination of data and code. Code that never changes. Data that is captured as the execution pointer passes over the expression that defines the block (i.e. the block "closes over" the current state of execution).

It is that latter bit that trips you up; when a block is created on the stack, it is created with slots to hold captured data, also on the stack.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文