2010-03-09 4 views
12

Мне интересно, для каких-либо других целей, кроме чистого любопытства (потому что никто не должен ВСЕГДА писать такой код!) О том, как поведение RAII мешей с использованием goto (прекрасная идея не так) ,Что происходит, когда мы объединяем RAII и GOTO?

class Two 
{ 
public: 
    ~Two() 
    { 
     printf("2,"); 
    } 
}; 

class Ghost 
{ 
public: 
    ~Ghost() 
    { 
     printf(" BOO! "); 
    } 
}; 

void foo() 
{ 
    { 
     Two t; 
     printf("1,"); 
     goto JUMP; 
    } 
    Ghost g; 
JUMP: 
    printf("3"); 
} 

int main() 
{ 
     foo(); 
} 

При запуске следующего кода в Visual Studio 2005 я получаю следующий вывод.

1,2,3 BOO! 

Однако я представлял себе, догадался, что надеялся 'BOO! на самом деле не появлялся, поскольку Ghost должен был никогда не быть экземпляром (IMHO, потому что я не знаю фактического ожидаемого поведения этого кода).

Что случилось?


Я просто понял, что если я создаю экземпляр явный конструктор для Призрака код не компилируется ...

class Ghost 
{ 
public: 
    Ghost() 
    { 
     printf(" HAHAHA! "); 
    } 
    ~Ghost() 
    { 
     printf(" BOO! "); 
    } 
}; 

Ах, тайна ...

+1

Я считаю, что поведение верное. В противном случае, как бы вы могли ссылаться на переменную g после JUMP? – leiz

+2

http://xkcd.com/292/ –

ответ

23

Стандартные говорит о это явно - с примером; 6.7/3 «Заявление о декларации» (выделено мной мной):

Переменные с автоматической продолжительностью хранения инициализируются каждый раз, когда выполняется их заявление-заявление. Переменные с автоматическим временем хранения, объявленные в блоке, уничтожаются при выходе из блока.

Можно передать в блок, но не таким образом, чтобы обходить декларации с инициализацией. Программа, которая перескакивает с точки, где локальная переменная с продолжительностью автоматического хранения не находится в области до точки, где она находится в области, плохо сформирована, если только переменная не имеет тип POD и объявлена ​​без инициализатора.

[Пример:

void f() 
{ 
    //... 
    goto lx; //ill-formed: jump into scope of a 
    //... 

ly: 
    X a = 1; 
    //... 

lx: 
    goto ly; //OK, jump implies destructor 
       //call for a, followed by construction 
       //again immediately following label ly 
} 

-end пример]

Так что, мне кажется, что поведение MSVC не является стандартам - Ghost не тип POD, так что компилятор должен выдать когда оператор goto закодирован, чтобы перепрыгнуть через него.

Пара других компиляторов, которые я пробовал (GCC и Digital Mars), выдает ошибки. Comeau выдает предупреждение (но, честно говоря, мой сценарий сборки для Comeau настроен на высокую совместимость с MSVC, поэтому он может следовать за намерениями Microsoft преднамеренно).

+1

Спасибо, что нашли место, где это определено в стандарте! Однако я задаюсь вопросом, не плохо ли это означает, что он должен или не должен компилироваться ... –

+0

«Неформованный» означает, что программа не «хорошо сформирована». Компиляторы должны принимать и правильно выполнять хорошо подготовленные программы. То есть, если оно «плохо сформировано», оно ошибочно. – greyfade

+0

@ Robert: Я добавил несколько слов о поведении MSVC здесь, как и следовало бы сделать изначально. –

0

Goto не радиоактивен. Выход из goto немного отличается от ухода за исключением. Ввод по goto должен быть продиктован удобством, а не пределами языка. Не зная, построен ли призрак или нет, это хорошая причина не делать этого.

Перейти перед конструктором. Если вы хотите вступить в игру после того, как какой-либо объект уже сконструирован, заключите его в новую область или иным образом решите свою жизнь самостоятельно.

0

В этом случае я нашел следующий подход полезным.

void foo() 
{ 
    { 
     Two t; 
     printf("1,"); 
     goto JUMP; 
    } 

    { 
     Ghost g; 
     // operations that use g. 
    } 

// g is out of scope, so following JUMP is allowed. 
JUMP: 
    printf("3"); 
} 

Ограничение объема переменной g в вашей функции foo() приведет к тому, что переход переходит к законному. Теперь мы не прыгаем с места, где g не инициализируется в место, где ожидается ожидание g.

Смежные вопросы