Рассмотрим следующий код:
# 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
кода, поскольку они ничего не сделают, когда выдается исключение.