简体   繁体   中英

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 (eg 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.

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).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM