2011-09-20 23 views
5

當我試圖在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上進行了測試。

回答

6

我想說它在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

相關問題