| 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); |