Есть условная легаси функция (2к строк) с кучей точек завершения.
long foo(...)
{
if (statement1)
return -1;
if (statement2)
return -2;
for (...)
{
if(...)
return -3;
...
}
...
}
Функция модифируется и возникает необходимость перед каждым return вызвать определенный cleanup код, обернуть этот код в локальный объект, который бы автоматически разрушался при завершении функции не получается.
Вариант обернуть тело функции в try-catch наверное не подходит т.к. функция частично перебрасывает исключения наверх, частично обрабатывает своими силами и наверняка будет некий сайд-эффект от такого способа.
Есть ли способы сделать это без дописывания cleanup-code к каждому return?
дело под виндой, vs2015
P.S. пока придумалось вместо каждого return вызывать лямбду/функцию, которая будет вызывать cleanup-code и делать return
Вам нужен scope guard.
Работает это примерно так:
FILE *f = std::fopen(...);
if (!f) throw ...;
FINALLY( std::fclose(f); )
// Тут используется `f`.
Здесь FINALLY
- это макрос, тот самый scope guard.
Код внутри scope guard вызывается не сразу, а после выхода из области видимости (у вас - после выхода из функции).
Реализацию scope guard можно нагуглить, а можно написать свою (это несложно).
Я обычно использую вот такой вариант:
namespace Macro
{
template <typename T> class FinallyObject
{
T func;
public:
FinallyObject(T &&func) : func(std::move(func)) {}
FinallyObject(const FinallyObject &) = delete;
FinallyObject &operator=(const FinallyObject &) = delete;
~FinallyObject()
{
func();
}
};
}
#define FINALLY_impl_cat(a, b) FINALLY_impl_cat_(a, b)
#define FINALLY_impl_cat_(a, b) a##b
#define FINALLY(...) \
::Macro::FinallyObject FINALLY_impl_cat(_finally_object_,__LINE__) \
([&]{ __VA_ARGS__ });
// Как обычный FINALLY, но выполняется только при выбросе исключения.
#define FINALLY_ON_THROW(...) \
::Macro::FinallyObject FINALLY_impl_cat(_finally_object_,__LINE__) \
([&, _finally_exc_depth_ = ::std::uncaught_exceptions()] \
{ if (::std::uncaught_exceptions() != _finally_exc_depth_) {__VA_ARGS__} });
// Наоборот, выполняется если вызов деструктора произошел из-за нормального
// выхода из scope, а не из-за исключения.
#define FINALLY_ON_SUCCESS(...) \
::Macro::FinallyObject FINALLY_impl_cat(_finally_object_,__LINE__) \
([&, _finally_exc_depth_ = ::std::uncaught_exceptions()] \
{ if (::std::uncaught_exceptions() == _finally_exc_depth_) {__VA_ARGS__} });
Вот переделанная версия, которая работает без С++17.
Предупреждение: В этом варианте мы вынуждены использовать std::uncaught_exception
вместо std::uncaught_exceptions
, поэтому в некоторых редких случаях обнаружение исключений (макросы FINALLY_ON_THROW
и FINALLY_ON_SUCCESS
) будут работать некорректно.
Например, если они используются внутри деструктора (в том числе в любой вызванной им функции), и этот деструктор был вызван из-за исключения, то макросы FINALLY_ON_THROW
и FINALLY_ON_SUCCESS
будут учитывать это исключение (первый вызовет свой код, а второй - нет). Это - неправильное поведение, так как учитываться должны только новые исключения (выброшенные после прохода выполнения через макрос).
namespace Macro
{
template <typename T> class FinallyObject
{
T func;
public:
FinallyObject(T &&func) : func(std::move(func)) {}
FinallyObject(FinallyObject &&) = default;
FinallyObject &operator=(const FinallyObject &) = delete;
~FinallyObject()
{
func();
}
};
template <typename T>
FinallyObject<T> MakeFinallyObject(T &&func)
{
return {std::move(func)};
}
}
#define FINALLY_impl_cat(a, b) FINALLY_impl_cat_(a, b)
#define FINALLY_impl_cat_(a, b) a##b
#define FINALLY(...) \
auto FINALLY_impl_cat(_finally_object_,__LINE__) = ::Macro::MakeFinallyObject([&]{ __VA_ARGS__ });
// Как обычный FINALLY, но выполняется только при выбросе исключения.
#define FINALLY_ON_THROW(...) \
FINALLY( if (::std::uncaught_exception()) {__VA_ARGS__} )
// Наоборот, выполняется если вызов деструктора произошел из-за нормального
// выхода из scope, а не из-за исключения.
#define FINALLY_ON_SUCCESS(...) \
FINALLY( if (!::std::uncaught_exception()) {__VA_ARGS__} )
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Есть вот такой вызов ajax, который работает по клику на option
Код в индекс хтмл
Хотите улучшить этот вопрос? Добавьте больше подробностей и уточните проблему, отредактировав это сообщение