@@ -63,7 +63,10 @@ namespace sr | |||
&& std::is_nothrow_move_constructible_v<D>) | |||
: resource(std::move_if_noexcept(other.resource.get()), scope_exit{[] { }}), | |||
deleter(std::move_if_noexcept(other.deleter.get()), scope_exit{[&other] { | |||
other.get_deleter()(other.resource.get()); | |||
if( other.execute_on_reset == true ) | |||
{ | |||
other.get_deleter()(other.resource.get()); | |||
} | |||
other.release(); }}), | |||
execute_on_reset(std::exchange(other.execute_on_reset, false)) | |||
{ |
@@ -168,5 +168,28 @@ namespace mock | |||
CopyMock(const CopyMock&) { } | |||
}; | |||
struct ConditionalThrowOnCopyDeleter | |||
{ | |||
ConditionalThrowOnCopyDeleter() { } | |||
ConditionalThrowOnCopyDeleter(const ConditionalThrowOnCopyDeleter&) | |||
{ | |||
if( throwOnNextCopy == true ) | |||
{ | |||
throw std::exception{}; | |||
} | |||
throwOnNextCopy = false; | |||
} | |||
MAKE_CONST_MOCK1(deleter, void(Handle)); | |||
void operator()(Handle h) const | |||
{ | |||
this->deleter(h); | |||
} | |||
static inline bool throwOnNextCopy{false}; | |||
}; | |||
} | |||
@@ -81,6 +81,15 @@ TEST_CASE("move-construction with copy", "[UniqueResource]") | |||
[[maybe_unused]] auto guard = std::move(movedFrom); | |||
} | |||
TEST_CASE("move-construction prevents double release", "[UniqueResource]") | |||
{ | |||
auto movedFrom = sr::unique_resource{Handle{3}, ConditionalThrowOnCopyDeleter{}}; | |||
movedFrom.release(); | |||
ConditionalThrowOnCopyDeleter::throwOnNextCopy = true; | |||
REQUIRE_THROWS([&movedFrom] { [[maybe_unused]] auto guard = std::move(movedFrom); }()); | |||
} | |||
TEST_CASE("move assignment calls deleter", "[UniqueResource]") | |||
{ | |||
auto moveFrom = sr::unique_resource{Handle{3}, deleter}; |