在尝试在Objective-C块中捕获堆栈上的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 ++ Objects”似乎表明它们是,但它们显然不在这里工作。这是编译器/运行时中的错误吗?这是在Mac OS X v10.6.8上的GCC 4.2.1,Apple build 5666上测试的。
答案 0 :(得分:6)
我要说它是海湾合作委员会的一个错误。
当我尝试使用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
后者遵循我对块文档的解释(并且是唯一没有公然破坏的版本)。