Я пишу службу Windows на C++ (Visual Studio 2022, C++20), и служба неожиданно завершилась в полевых условиях. Это было связано с обновлением, которое я сделал спустя много времени после написания исходного кода, где внутренней функции f требовался установленный флаг на время ее выполнения, а затем возвращался в неустановленное состояние при выходе из функции. Чтобы внести это изменение, я просто добавил пару строк кода, как показано ниже — SetFlag(true) иscope_guard:
Код: Выделить всё
void outer() {
while(true) {
try {
many_nested_functions_leading_to_f();
}
catch (const MyException&) {
/* handle exception and then retry with the outer while loop */
}
}
}
void SetFlag(bool) {
/* can throw MyException */
}
void f() {
/* We need flag to be true for the duration of this function */
SetFlag(true);
auto guardClearFlag = sg::make_scope_guard([] { SetFlag(false); });
/* complicated flow control, many return paths .. */
}
предназначен для выдачи ошибок, и в этом случае я хочу, чтобы выполнение возобновилось вверх по стеку вызовов внешней функции, где я очищаю и затем повторяю попытку, повторяя цикл while. Это, конечно, классическая проблема, когда деструкторы выбрасывают ошибки, и я потратил некоторое время, погружаясь в эту кроличью нору, чтобы понять технические детали и лучшие практики.
В моем случае я обнаружил, что самым простым и понятным решением было обернуть f кодом, который устанавливает и очищает флаг:
Код: Выделить всё
void fWithFlagTrue() {
/* complicated flow control, many return paths .. */
}
void f() {
SetFlag(true);
fWithFlagTrue();
SetFlag(false);
}
Это было довольно неудовлетворительно, потому что:
- Мне очень нравится мой оригинальный двухстрочный патч. Я устанавливаю флаг вверху, и с помощьюscope_guard я могу гарантировать, что флаг будет очищен при выходе из функции.
- Мне действительно не нравится мое решение, поскольку в нем много шаблонов, и кажется, что должно быть менее утомительное идиоматическое решение.
Я понимаю, что иметь два активных исключения одновременно проблематично, а прерывать раскрутку стека - это очень проблематично. В моем случае, если f выдает ошибку, я хочу, чтобы выполнение завершилось во внешнем, как я описал выше, и состояние флага не имеет значения. Если SetFlag выдает то же самое: я просто хочу, чтобы выполнение заканчивалось внешним. Поэтому я думаю, что мое решение многословно, но это то, чего я хочу логически. Я просто надеюсь, что есть что-то близкое к моему оригинальному двухстрочному патчу, который сможет достичь этой цели.
Подробнее здесь:
https://stackoverflow.com/questions/798 ... -may-throw