#include #include using namespace std; class Resource { }; class Resource_Control { public: Resource_Control(int max) : max_copies{max}, current_copies{1} {} friend class Limited_Resource; private: const int max_copies; int current_copies; }; class Limited_Resource { public: Limited_Resource(int max) : r{ new Resource{} }, c{ new Resource_Control{max} } {} Limited_Resource(Limited_Resource const& lhs) : r{}, c{} { if ( lhs.c->current_copies < lhs.c->max_copies ) { ++lhs.c->current_copies; r = new Resource{*lhs.r}; c = lhs.c; } else { throw runtime_error{"too many copies"}; } } Limited_Resource(Limited_Resource && lhs) : r{}, c{} { swap(lhs.r, r); swap(lhs.c, c); } Limited_Resource& operator=(Limited_Resource const& lhs) { Limited_Resource copy{lhs}; swap(copy.r, r); swap(copy.c, c); return *this; } Limited_Resource& operator=(Limited_Resource && lhs) { swap(lhs.r, r); swap(lhs.c, c); return *this; } ~Limited_Resource() { if ( r != nullptr ) { --c->current_copies; delete r; if ( c->current_copies == 0 ) delete c; } } private: Resource* r; Resource_Control* c; }; #define CATCH_CONFIG_MAIN #include "catch.hpp" TEST_CASE("basic limit") { Limited_Resource one{1}; CHECK_THROWS(Limited_Resource{one}); } TEST_CASE("object independent limit") { Limited_Resource one{1}; Limited_Resource other{1}; CHECK_THROWS(Limited_Resource{one}); CHECK_THROWS(Limited_Resource{other}); } TEST_CASE("higher limit") { Limited_Resource three{3}; Limited_Resource three2{three}; Limited_Resource three3{three}; CHECK_THROWS(Limited_Resource{three}); } TEST_CASE("limit with move") { Limited_Resource one{1}; Limited_Resource one1{std::move(one)}; CHECK_THROWS(Limited_Resource{one1}); } TEST_CASE("limit with assign") { Limited_Resource two{2}; Limited_Resource other{1}; other = two; CHECK_THROWS(Limited_Resource{two}); CHECK_THROWS(Limited_Resource{other}); }