堆栈中的C++类实例是否可以被Objective-C块捕获?

问题描述:

当我试图在Objective-C块的堆栈中捕获一个C++类的实例时,我看到一些奇怪的行为。请看下面的代码:堆栈中的C++类实例是否可以被Objective-C块捕获?

#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; 
} 

人们预计,当局部变量test得到由块blk拍摄的,它有一个一致的状态。但是,情况并非如此。这段代码的输出如下:

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

所以当地Test实例块看到已呼吁其析构函数!你用它做的任何事情都是未定义的行为,这很可能导致崩溃(例如,如果析构函数删除了一个指针而没有将其设置为NULL)。

Objective-C块支持C++类实例变量吗? Block Programming Topics节“C++对象”似乎表明他们是,但他们显然不在这里工作。这是编译器/运行时的错误吗?这在Mac OS X v10.6.8上的GCC 4.2.1,Apple build 5666上进行了测试。

我想说它在GCC中的一个错误。

当我用GCC尝试,我得到:

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

但使用LLVM 2.0:

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

后者遵循块我的文档的解释(并且是唯一的版本,没有被公然破坏)。

+1

甜 - 你说得对:-)当访问块之外声明的std :: map的元素时,我遇到了BAD_ACCESS异常。 [BlockLanguageSpec](http://clang.llvm.org/docs/BlockLanguageSpec.txt)指出,“堆栈本地对象通过拷贝常量构造函数复制到块中”,所以它应该工作,因此是错误。切换到LLVM 3.0解决了这个问题。 – Sebastian