Выброс массива локально в блок try

Из С++ Primer 18.1.1:

Если выражение [throw] имеет массив или тип функции, выражение преобразуется в соответствующий тип указателя.

Как получается, что эта программа может производить корректный вывод 9876543210 (g++ 5.2.0)?

#include <iostream>
using namespace std;

int main(){

    try{
        int a[10] = {9,8,7,6,5,4,3,2,1,0};
        throw a;
    }
    catch(int* b) { for(int i = 0; i < 10; ++i) cout << *(b+i); }

}

Из цитаты throw a создаст объект исключения типа int*, который является указателем на первый элемент массива. Но, конечно, элементы массива a будут уничтожены при выходе из блока try и введите предложение catch, так как мы изменим область блока? Я получаю ложное положительное значение или элементы массива "оставлены в покое" (не удаляются) в течение срока действия предложения catch?

Ответы

Ответ 1

Разыменование висячего указателя Undefined Поведение.

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

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

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

Также обратите внимание, что gcc-оптимизация довольно печально для того, чтобы полагаться на программу, не вызывающую поведение Undefined. Довольно часто, если у вас есть поведение Undefined, неоптимизированная версия работает, но как только вы включаете оптимизацию, она начинает делать что-то совершенно неожиданное.

Ответ 2

Но, конечно, элементы массива a будут уничтожены, когда мы выйдем из блока try и войдем в предложение catch, так как мы изменим область видимости блока?

Правильно.

Я получаю ложное положительное значение или элементы массива "оставлены в покое" (не удаляются) в течение срока действия предложения catch?

Они не "оставлены одни". Массив уничтожается, как вы правильно предполагали. Программа обращается к недопустимой памяти. Поведение undefined.

Как получается, что эта программа может производить правильный вывод 9876543210 (g++ 5.2.0)?

Нет правильного вывода, если поведение undefined. Программа может произвести то, что она сделала, потому что она может производить любой вывод, когда поведение undefined.

Рассуждение о UB обычно бессмысленно, но в этом случае содержимое недопустимой памяти может быть идентичным, если часть памяти еще не была перезаписана программой.

Ответ 3

В этой главе вы найдете следующее предупреждение:

Для броска указателя требуется, чтобы объект, на который указатель точки существуют везде, где находится соответствующий обработчик.

поэтому ваш пример будет действителен, если массив a был статическим или глобальным, иначе его UB. Или (как пишет Ян Худек в комментарии) в закрывающем блоке инструкции try/catch.