Могут ли экземпляры класса C ++ в стеке быть захвачены блоками Objective-C? - PullRequest
5 голосов
/ 21 сентября 2011

Я вижу странное поведение, когда пытаюсь перехватить экземпляр класса 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).

Поддерживаются ли переменные экземпляра класса C ++ блоками Objective-C? Темы блочного программирования раздел "Объекты C ++", кажется, указывает, что они есть, но они явно не работают здесь. Это ошибка в компиляторе / среде выполнения? Это было проверено на GCC 4.2.1, Apple build 5666, на Mac OS X v10.6.8.

1 Ответ

6 голосов
/ 21 сентября 2011

Я бы сказал, что это ошибка в 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

Последнее следует моей интерпретации документации для блоков (и это единственная версия, которая не является вопиюще нарушенной).

...