Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can C++ class instances on the stack be captured by Objective-C blocks?

I'm seeing some strange behavior when trying to capture an instance of a C++ class on the stack in an Objective-C block. Consider the following code:

#import <Foundation/Foundation.h>
#include <stdio.h>

struct Test
{
  Test() : flag(0) { printf("%p default constructor\n", this); }
  Test(const Test& other) : flag(0) { printf("%p copy constructor\n", this); }
  ~Test() { flag = 1; printf("%p destructor\n", this); }

  int flag;
};

int main(int argc, char **argv)
{
  NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

  Test test;
  void (^blk)(void) = ^(void)
    {
      printf("flag=%d (test=%p)\n", test.flag, &test);
    };
  printf("about to call blk\n");
  blk();

  [pool release];

  return 0;
}

One would expect that when the local variable test gets captured by the block blk, it has a consistent state. However, that is not the case. The output of this code is the following:

0x7fff5fbff650 default constructor
0x7fff5fbff630 copy constructor
about to call blk
0x7fff5fbff5d0 copy constructor
0x7fff5fbff5d0 destructor
flag=1 (test=0x7fff5fbff5d0)
0x7fff5fbff630 destructor
0x7fff5fbff650 destructor

So the local Test instance that the block sees has had its destructor called! Anything you do with it is undefined behavior, which would very likely lead to a crash (e.g. if the destructor deleted a pointer without setting it to NULL).

Are C++ class instance variables supported by Objective-C blocks? The Block Programming Topics section "C++ Objects" seems to indicate that they are, but they clearly aren't working here. Is this a bug in the compiler/runtime? This was tested on GCC 4.2.1, Apple build 5666, on Mac OS X v10.6.8.

like image 259
Adam Rosenfield Avatar asked Sep 20 '11 21:09

Adam Rosenfield


People also ask

What is __ block Objective-C?

__block is a storage qualifier that can be used in two ways: Marks that a variable lives in a storage that is shared between the lexical scope of the original variable and any blocks declared within that scope. And clang will generate a struct to represent this variable, and use this struct by reference(not by value).

How do blocks work in Objective-C?

Blocks are a language-level feature added to C, Objective-C and C++, which allow you to create distinct segments of code that can be passed around to methods or functions as if they were values. Blocks are Objective-C objects, which means they can be added to collections like NSArray or NSDictionary .

Is Objective-C faster than C?

Objective-C is slightly slower than straight C function calls because of the lookups involved in its dynamic nature.


1 Answers

I'd say its a bug in GCC.

When I try it with GCC, I get:

0x7fff5fbff5d0 default constructor
0x7fff5fbff5c0 copy constructor
about to call blk
0x7fff5fbff570 copy constructor
0x7fff5fbff570 destructor
flag=1 (test=0x7fff5fbff570)
0x7fff5fbff5c0 destructor
0x7fff5fbff5d0 destructor

But using LLVM 2.0:

0x7fff5fbff610 default constructor
0x7fff5fbff600 copy constructor
about to call blk
flag=0 (test=0x7fff5fbff600)
0x7fff5fbff600 destructor
0x7fff5fbff610 destructor

The latter follows my interpretation of the documentation for blocks (and is the only version that isn't flagrantly broken).

like image 106
adpalumbo Avatar answered Sep 19 '22 05:09

adpalumbo