Last active
December 21, 2016 10:48
-
-
Save OpenNingia/bb664c35243c9d89f992a2bd305ea341 to your computer and use it in GitHub Desktop.
Revisions
-
OpenNingia revised this gist
Dec 21, 2016 . 1 changed file with 1 addition and 1 deletion.There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -110,7 +110,7 @@ TEST_CASE("safe_ptr can be copied if the container supports it", "[constructor]" auto sptr2 = sptr; REQUIRE(*sptr == *sptr2); // this fails to compile because unique_ptr is not copyable // auto sptr3 = mem::make_safe_unique<std::string>("hello world!"); // auto sptr4 = sptr3; } -
OpenNingia created this gist
Dec 21, 2016 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,135 @@ #define CATCH_CONFIG_MAIN #include "catch.hpp" #include <memory> #include <utility> #include <exception> namespace mem { class null_dereference_exception : public std::exception { }; template<typename T, typename Container = std::unique_ptr<T>> class safe_ptr { public: safe_ptr() { } safe_ptr(T* ptr) : data_(ptr) { } // to support make_safe_* safe_ptr(Container && src) : data_(std::move(src)) { } // only enabled if container supports it safe_ptr(safe_ptr && o) : data_(std::move(o.data_)) { } // only enabled if container supports it safe_ptr(safe_ptr const & o) : data_(o.data_) { } T & operator*() { throw_if_null(); return *data_; } T const & operator*() const { throw_if_null(); return *data_; } T const * operator->() const { throw_if_null(); return get(); } T * operator->() { throw_if_null(); return get(); } T* get() { return data_.get(); } T const * get() const { return data_.get(); } void reset() { data_.reset(); } operator bool() const { return (bool)data_; } private: void throw_if_null() { if ( !data_ ) throw null_dereference_exception(); } Container data_; }; template<typename T, typename... Args> auto make_safe_unique(Args&&... a) -> safe_ptr<T, std::unique_ptr<T>> { return safe_ptr<T, std::unique_ptr<T>>(std::make_unique<T>(std::forward<Args>(a)...)); } template<typename T, typename... Args> auto make_safe_shared(Args&&... a) -> safe_ptr<T, std::shared_ptr<T>> { return safe_ptr<T, std::shared_ptr<T>>(std::make_shared<T>(std::forward<Args>(a)...)); } } TEST_CASE("safe_ptr can be instantiated with a pointer", "[constructor]") { auto str = new std::string(); mem::safe_ptr<std::string> sptr(str); REQUIRE(str == sptr.get()); } TEST_CASE("safe_ptr can be instantiated by moving a unique pointer", "[constructor]") { auto str = std::make_unique<std::string>("hello world!"); mem::safe_ptr<std::string> sptr(std::move(str)); REQUIRE(!str); REQUIRE(*sptr == std::string("hello world!")); } TEST_CASE("safe_ptr can be instantiated by moving a shared pointer", "[constructor]") { auto str = std::make_shared<std::string>("hello world!"); mem::safe_ptr<std::string, std::shared_ptr<std::string>> sptr(std::move(str)); REQUIRE(!str); REQUIRE(*sptr == std::string("hello world!")); } TEST_CASE("safe_ptr can be instantiated with the make_safe_unique idiom", "[constructor]") { auto sptr = mem::make_safe_unique<std::string>("hello world!"); REQUIRE(*sptr == std::string("hello world!")); } TEST_CASE("safe_ptr can be instantiated with the make_safe_shared idiom", "[constructor]") { auto sptr = mem::make_safe_shared<std::string>("hello world!"); REQUIRE(*sptr == std::string("hello world!")); } TEST_CASE("safe_ptr can be copied if the container supports it", "[constructor]") { auto sptr = mem::make_safe_shared<std::string>("hello world!"); auto sptr2 = sptr; REQUIRE(*sptr == *sptr2); // this raise a compiler error because unique_ptr is not copyable // auto sptr3 = mem::make_safe_unique<std::string>("hello world!"); // auto sptr4 = sptr3; } TEST_CASE("safe_ptr supports simple bool operator", "[operators]") { mem::safe_ptr<std::string> strp1; auto strp2 = mem::make_safe_unique<std::string>("Hello world!"); REQUIRE_FALSE(strp1); REQUIRE(strp2); } TEST_CASE("safe_ptr throw exception if deferencing nullptr", "[exceptions]") { mem::safe_ptr<std::string> strp1; auto strp2 = mem::make_safe_unique<std::string>("Hello world!"); REQUIRE_THROWS_AS(*strp1, mem::null_dereference_exception); REQUIRE_NOTHROW(*strp2); REQUIRE_THROWS_AS(strp1->c_str(), mem::null_dereference_exception); REQUIRE_NOTHROW(strp2->c_str()); }