2011-09-20 8 views
5

Sto osservando un comportamento strano durante il tentativo di acquisire un'istanza di una classe C++ nello stack in un blocco Objective-C. Si consideri il seguente codice:Le istanze di classe C++ nello stack possono essere catturate dai blocchi 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; 
} 

Ci si aspetterebbe che, quando la variabile locale test viene catturato dal blocco blk, ha uno stato coerente. Tuttavia, questo non è il caso. L'uscita di questo codice è il seguente:

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

Così il locale Test istanza che vede il blocco ha avuto il suo distruttore chiamato! Qualsiasi cosa tu faccia con esso è un comportamento indefinito, che molto probabilmente porterà ad un crash (ad esempio se il distruttore ha cancellato un puntatore senza impostarlo su NULL).

Le variabili di istanza di classe C++ sono supportate dai blocchi Objective-C? La sezione Block Programming Topics "Oggetti C++" sembra indicare che lo sono, ma chiaramente non funzionano qui. È un bug nel compilatore/runtime? Questo è stato testato su GCC 4.2.1, Apple build 5666, su Mac OS X v10.6.8.

risposta

6

Direi che è un bug in GCC.

Quando provo con GCC, ottengo:

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

Ma usando LLVM 2.0:

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

Quest'ultimo segue la mia interpretazione della documentazione per i blocchi (ed è l'unica versione che non è rotto in modo flagrante).

+1

Dolce - hai ragione :-) Mi sono imbattuto in eccezioni BAD_ACCESS quando accedevo agli elementi di una std :: map dichiarata all'esterno del blocco. Il [BlockLanguageSpec] (http://clang.llvm.org/docs/BlockLanguageSpec.txt) afferma che "Gli oggetti locali dello stack vengono copiati in un blocco tramite un costruttore di copia const.", Quindi dovrebbe funzionare e quindi è un bug. Passare a LLVM 3.0 ha risolto il problema. – Sebastian

Problemi correlati