гарантия исключения без бросков и переполнение стека

Есть несколько специальных функций, которые обычно гарантируют, что исключения не будут выбрасываться, например:

  • деструкторы
  • swap метод

Рассмотрим следующее swap реализация, как указано в этот ответ:

friend void swap(dumb_array& first, dumb_array& second)
{
using std::swap;

swap(first.mSize, second.mSize);
swap(first.mArray, second.mArray);  // What if stack overlow occurs here?
}

Он использует два swap функции — для целого числа и для указателя. Что если вторая функция вызовет переполнение стека? Объекты будут повреждены. Я думаю, что это не std::exception, это какое-то системное исключение, вроде Win32-exception, Но теперь мы не можем гарантировать отсутствие бросков, так как мы вызываем функцию.

Но все авторитетные источники просто используют swap как будто все в порядке, здесь не будет никаких исключений. Зачем?

0

Решение

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

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

Если вы обеспокоены, вы можете пометить swap функционировать как noexcept, Затем в соответствующей реализации любое исключение, которое пытается выйти из функции, приведет к тому, что программа terminate(), То есть он выполняет noexcept контракт по стоимости вывоза вашей программы.

4

Другие решения

Что если вторая функция вызовет переполнение стека?

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

Но теперь мы не можем гарантировать отсутствие бросков

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

Но все авторитетные источники просто используют swap, как будто все в порядке, здесь не будет никаких исключений. Зачем?

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

Полезно классифицировать функции в соответствии с гарантиями их исключений:

  • Базовый: исключения оставляют все в допустимом, но неопределенном состоянии
  • Сильный: исключения оставляют государство без изменений
  • Безбросок: без исключений.

Общепринятым подходом к предоставлению «сильной» гарантии является:

  • сделать работу, которая может бросить на временную копию государства
  • поменяйте местами эту копию с текущим состоянием (требуя операции без броска)
  • уничтожить старое состояние (требующий не бросающего деструктора)

Если у вас нет гарантии отсутствия бросков от этих операций, то более сложно и, возможно, невозможно предоставить надежную гарантию.

2

По вопросам рекламы [email protected]