std::enable_if_t<std::is_constructible<Deleter, D>::value, int> = 0, | std::enable_if_t<std::is_constructible<Deleter, D>::value, int> = 0, | ||||
std::enable_if_t<std::is_lvalue_reference<D>::value, int> = 0 | std::enable_if_t<std::is_lvalue_reference<D>::value, int> = 0 | ||||
> | > | ||||
explicit scope_guard_t(D&& deleter) : m_deleter(deleter), | |||||
explicit scope_guard_t(D&& deleter) try : m_deleter(deleter), | |||||
m_execute_on_destruction(true) | m_execute_on_destruction(true) | ||||
{ | { | ||||
} | } | ||||
catch( ... ) | |||||
{ | |||||
deleter(); | |||||
throw; | |||||
} | |||||
scope_guard_t(const scope_guard_t&) = delete; | scope_guard_t(const scope_guard_t&) = delete; | ||||
template<class Deleter> | template<class Deleter> | ||||
scope_guard_t<Deleter> scope_guard(Deleter&& deleter) noexcept | |||||
scope_guard_t<std::decay_t<Deleter>> scope_guard(Deleter&& deleter) noexcept | |||||
{ | { | ||||
return scope_guard_t<Deleter>{std::move(deleter)}; | |||||
return scope_guard_t<std::decay_t<Deleter>>{std::forward<Deleter>(deleter)}; | |||||
} | } | ||||
} | } |
MAKE_MOCK0(deleter, void()); | MAKE_MOCK0(deleter, void()); | ||||
}; | }; | ||||
struct ThrowOnCopyMock | |||||
{ | |||||
ThrowOnCopyMock() = default; | |||||
ThrowOnCopyMock(const ThrowOnCopyMock&) | |||||
{ | |||||
throw std::exception{}; | |||||
} | |||||
MAKE_CONST_MOCK0(deleter, void()); | |||||
void operator()() const | |||||
{ | |||||
this->deleter(); | |||||
} | |||||
ThrowOnCopyMock& operator=(const ThrowOnCopyMock&) | |||||
{ | |||||
throw std::exception{}; | |||||
} | |||||
}; | |||||
CallMock m; | CallMock m; | ||||
void deleter() | void deleter() | ||||
{ | { | ||||
m.deleter(); | m.deleter(); | ||||
static_cast<void>(guard); | static_cast<void>(guard); | ||||
} | } | ||||
TEST_CASE("deleter called and rethrow on copy exception", "[ScopeGuard]") | |||||
{ | |||||
REQUIRE_THROWS([] { | |||||
const ThrowOnCopyMock noMove; | |||||
REQUIRE_CALL(noMove, deleter()); | |||||
sr::scope_guard_t<decltype(noMove)> guard{noMove}; | |||||
}()); | |||||
} | |||||
TEST_CASE("deleter is not called if released", "[ScopeGuard]") | TEST_CASE("deleter is not called if released", "[ScopeGuard]") | ||||
{ | { | ||||
REQUIRE_CALL(m, deleter()).TIMES(0); | REQUIRE_CALL(m, deleter()).TIMES(0); |