Выброс массива локально в блок 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.