Есть несколько специальных функций, которые обычно гарантируют, что исключения не будут выбрасываться, например:
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
как будто все в порядке, здесь не будет никаких исключений. Зачем?
В общем, вы не можете справиться с нехваткой стека. Стандарт не говорит о том, что происходит, если у вас закончился стек, и не говорит о том, что такое стек, каков его объем и т. Д. Операционные системы могут позволить вам управлять им во время сборки исполняемого файла или при его запуске. и все это не имеет значения, если вы пишете код библиотеки, поскольку вы не можете контролировать, какой объем стека имеет процесс или сколько уже было использовано до того, как пользователь вызовет вашу библиотеку.
Вы можете предположить, что переполнение стека приводит к тому, что ОС делает что-то внешний по отношению к вашей программе. Очень простая ОС может просто позволить ей выйти из себя странно (неопределенное поведение), серьезная ОС может сдуть процесс, или, если вам действительно не повезет, она выдаст некое определяемое реализацией исключение. Я на самом деле не знаю, предлагает ли Windows исключение SEH для переполнения стека, но если это так, то, вероятно, лучше не включать его.
Если вы обеспокоены, вы можете пометить swap
функционировать как noexcept
, Затем в соответствующей реализации любое исключение, которое пытается выйти из функции, приведет к тому, что программа terminate()
, То есть он выполняет noexcept
контракт по стоимости вывоза вашей программы.
Что если вторая функция вызовет переполнение стека?
Тогда ваша программа находится в неисправимом неисправном состоянии, и нет практического способа справиться с ситуацией. Надеемся, что переполнение уже вызвало ошибку сегментации и завершило программу.
Но теперь мы не можем гарантировать отсутствие бросков
Я никогда не сталкивался с реализацией, которая выдала бы исключение в этом состоянии, и я был бы довольно напуган, если бы это произошло.
Но все авторитетные источники просто используют swap, как будто все в порядке, здесь не будет никаких исключений. Зачем?
Авторитетные источники, которые я читал (как этот, например) не «просто используйте его, как будто все в порядке»; они говорят, что если у вас (например) нет броска swap
функция и деструктор без метания, затем Вы можете предоставить гарантии безопасности исключений от функций, которые их используют.
Полезно классифицировать функции в соответствии с гарантиями их исключений:
Общепринятым подходом к предоставлению «сильной» гарантии является:
Если у вас нет гарантии отсутствия бросков от этих операций, то более сложно и, возможно, невозможно предоставить надежную гарантию.