Рассмотрим следующий код:
# include <exception>
# include <cassert>
# define INLINE [[gnu::always_inline]]
template <class F>
class scope_failure
{
F f;
public:
constexpr INLINE scope_failure(F &&func) noexcept:
f{std::move(func)}
{}
INLINE ~scope_failure() noexcept
{
if (std::uncaught_exceptions())
f();
}
};
void F1() {
scope_failure s{[]() noexcept { assert(false); }};
}
int main() {
F1();
}
Как видите, в void F1()
нет исключений, поэтому ~scope_failure
не должен делать ничего, и это может быть даже оптимизировано, потому что это имеет значение только в контексте, к которому выдается исключение.
Я скомпилировал код, используя clang++-6.0 -std=c++17 -S
и получается, что такой оптимизации не происходит. Я хочу спросить, есть ли способ сделать это?
Изменить, объяснение мотивации для этой оптимизации:
ИМХО, это очень важная оптимизация. Это позволяет zero-cost abstraction
для кода, который использует либо scope_success
или же scope_failure
сделать cleanup
или сделать assertion
в
это, то есть часть contract programming
,
Более того, если компиляторы могут оптимизировать этот код, они также могут оптимизировать код зарегистрированного destructor
за exception-handling
код для обратного вызова, напр. удалить if
в scope_failure
и выполнить зарегистрированную функцию обратного вызова напрямую или удалить регистрацию scope_success
за exception-handling
код для них ничего не будет делать, когда выдается исключение.
Задача ещё не решена.
Других решений пока нет …