10

考虑以下 C++ 方法:

class Worker{
....
private Node *node
};

void Worker::Work()
{
    NSBlockOperation *op=[NSBlockOperation blockOperationWithBlock:  ^{
            Tool hammer(node);
            hammer.Use();
          }];
    ....
    }

块在捕获“节点”时究竟捕获了什么?块的语言规范http://clang.llvm.org/docs/BlockLanguageSpec.html对其他情况很清楚:

在复合语句范围内使用的变量以正常方式绑定到块,但自动(堆栈)存储中的变量除外。因此,人们可以按预期访问函数和全局变量,以及静态局部变量。[考验我]

在 Block 的复合语句中引用的本地自动(堆栈)变量由 Block 作为 const 副本导入和捕获。

但是在这里,我们是否捕获了this的当前值?使用 Worker 的复制构造函数的副本还是对节点存储位置的引用?

特别是,假设我们说

 {
 Worker fred(someNode);
 fred.Work();
 }

当块运行时,对象 fred 可能不再存在。节点的价值是什么?(假设底层 Node 对象永远存在,但 Workers 来来去去。)

相反,如果我们写

void Worker::Work()
    {
        Node *myNode=node;
        NSBlockOperation *op=[NSBlockOperation blockOperationWithBlock:  ^{
                Tool hammer(myNode);
                hammer.Use();
              }];
        ....
        }

结果不一样吗?

4

2 回答 2

11

根据此页面

通常,您可以在块中使用 C++ 对象。在成员函数中,对成员变量和函数的引用是通过隐式导入的this指针进行的,因此看起来是可变的。如果复制块,有两个注意事项:

  • 如果您有一个 __block 存储类来存储基于堆栈的 C++ 对象,则使用通常的复制构造函数。
  • 如果您在块中使用任何其他基于 C++ 堆栈的对象,则它必须具有 const 复制构造函数。然后使用该构造函数复制 C++ 对象。

根据经验,我观察到它 const 将this指针复制到块中。如果块执行时指向的 C++ 实例this不再位于该地址(例如,如果Worker::Work()调用的 Worker 实例在更高的帧上堆栈分配),那么您将获得 EXC_BAD_ACCESS 或更糟(即指针别名)。所以看起来:

  • 它是捕获this,而不是按值复制实例变量。
  • this没有做任何事情来保持活着所指向的对象。

或者,如果我引用一个本地堆栈分配(即在此堆栈帧/范围中声明)C++ 对象,我观察到它的复制构造函数在它最初被块捕获时被调用,然后在复制块时再次调用(对于例如,当您将操作入队时由操作队列。)

具体解决您的问题:

但是在这里,我们是否捕获了 的当前值this?使用 Worker 的复制构造函数的副本?还是对节点存储位置的引用?

我们捕获this. intptr_t将其视为if 有帮助的 const 副本。

当块运行时,该对象fred可能不再存在。的价值是node多少?(假设底层 Node 对象永远存在,但 Workers 来来去去。)

在这种情况下,this已经按值捕获并且node实际上是一个带有值的指针,this + <offset of node in Worker>但是由于 Worker 实例已经消失,它实际上是一个垃圾指针。

除了那些文档中描述的内容之外,我不会推断出任何魔法或其他行为。

于 2013-08-28T17:05:52.700 回答
1

在 C++ 中,当你写一个实例变量时node,没有显式写something->node,它是隐式的this->node。(类似于Objective-C,如果你写一个实例变量node,没有显式写something->node,它是隐式的self->node。)

所以正在使用的变量是this,它就是this被捕获的。(技术上this在标准中被描述为它自己的一个单独的表达式类型,而不是一个变量;但出于所有意图和目的,它充当类型的隐式局部变量Worker *const。)与所有非__block变量一样,捕获它会const复制this.

块在捕获 Objective-C 对象指针类型的变量时具有内存管理语义。但是,this它没有 Objective-C 对象指针类型,因此在内存管理方面没有做任何事情。(无论如何,在 C++ 内存管理方面没有什么可以做的。)所以是的,在块运行时,指向的 C++ 对象this可能是无效的。

于 2013-08-28T23:01:58.240 回答