C ++ block object semantics

Consider the following C ++ method:

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

What does block capture actually do when it captures a "node"? The language specification for blocks, http://clang.llvm.org/docs/BlockLanguageSpec.html , is understandable for other cases:

Variables used within the compound operator are bound to the block in the usual manner, with the exception of those stored in the automatic (stack) storage. Thus, you can access functions and global variables, as you would expect, as well as static local variables. [TestMe]

Local automatic (stack) variables specified in the compound block instruction are imported and fixed by the block as copies of const.

But here we fix the current value of this ? Copy this using the Workers copy constructor? Or a link to where node is stored?

In particular, suppose that

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

The fred object can no longer exist when a block starts. What is the value of node ? (Suppose the underlying Node objects live forever, but the Workers come and go.)

If instead we wrote

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

- is the result different?

+8
objective-c block objective-c ++
source share
2 answers

According to this page :

In general, you can use C ++ objects inside a block. Inside a member of a function, references to member variables and functions through an implicitly imported this pointer and therefore mutable displayed. There are two considerations that apply if a block is copied:

  • If you have a __block storage class for what would be based on a C ++ object, then the usual copy constructor is used.
  • If you use any other C ++-based object from within the block, it must have a const const constructor. Then the C ++ object is copied using this constructor.

Empirically, I observe that it const copies the this pointer into a block. If the C ++ instance pointed to by this is no longer at that address when the block is executed (for example, if the Worker instance that Worker::Work() is called on has been stacked on a higher frame), you will get EXC_BAD_ACCESS or worse (i.e. smoothing the pointer). Thus, it seems that:

  • It writes this , rather than copying instance variables by value.
  • Nothing is done to make the object pointed to by this alive.

Alternatively, if I reference a C ++ object with a local stack (i.e. declared in this frame / stack area), I see that its copy constructor is called when it is initially captured by the block, and then again when the block (for example, in the operation queue when queuing the operation).

To specifically ask your questions:

But here we fix the current value of this ? Copy this using Workers copy constructor? Or a link to where node is stored?

We write this . Consider this const-copy intptr_t if that helps.

The fred object may not exist when the block starts. What is the meaning of node ? (Suppose the base node objects live forever, but the workers come and go.)

In this case, this was written by value, and node actually a pointer with the value this + <offset of node in Worker> , but since the Worker instance does not work, it is actually a garbage pointer.

I would not do any magic or other behavior besides what is described in these documents.

+8
source share

In C ++, when you write a node instance variable, without explicitly writing something->node , it implicitly this->node . (Similar to Objective-C, if you write an instance variable of node , without explicitly writing something->node , it is implicitly self->node .)

So the variable that is used is this , and it is this . (Technically, this described in the standard as a separate type of expression, not a variable, but for all purposes and purposes it acts as an implicit local variable of type Worker *const .) As with all non __block variables, capturing it gives a const copy of this .

Blocks have memory management semantics when they commit a variable of type pointer to an Objective-C type. However, this does not have an Objective-C object pointer type, so nothing is done from the point of view of memory management. (In any case, nothing can be done from the point of view of C ++ memory management.) So yes, the C ++ object pointed to by this may not be valid at the time the block starts.

+1
source share

All Articles