#ifndef MESSMER_CPP_UTILS_UNIQUE_REF_H #define MESSMER_CPP_UTILS_UNIQUE_REF_H #include #include #include "macros.h" namespace cpputils { /** * unique_ref behaves like unique_ptr, but guarantees that the pointer points to a valid object. * You can create objects using make_unique_ref (works like make_unique for unique_ptr). * * If you happen to already have a unique_ptr, you can call nullcheck(unique_ptr), * which returns optional>. * Take care that this should be used very rarely, since it circumvents parts of the guarantee. * It still protects against null pointers, but it does not guarantee anymore that the pointer points * to a valid object. It might hold an arbitrary non-null memory location. * * Caution: There is one way a unique_ref can actually hold a nullptr. * It will hold a nullptr after its value was moved to another unique_ref. * Never use the old instance after moving! */ template class unique_ref { public: unique_ref(unique_ref&& from): _target(std::move(from._target)) {} unique_ref& operator=(unique_ref&& from) { _target = from._target; } typename std::add_lvalue_reference::type operator*() const { return *_target; } T* operator->() const { return get(); } T* get() const { return _target.get(); } void swap(unique_ref&& rhs) { _target.swap(rhs._target); } private: unique_ref(std::unique_ptr target): _target(std::move(target)) {} template friend unique_ref make_unique_ref(Args&&... args); template friend boost::optional> nullcheck(std::unique_ptr ptr); std::unique_ptr _target; DISALLOW_COPY_AND_ASSIGN(unique_ref); }; template inline unique_ref make_unique_ref(Args&&... args) { return unique_ref(std::make_unique(std::forward(args)...)); } template inline boost::optional> nullcheck(std::unique_ptr ptr) { if (ptr.get() != nullptr) { return unique_ref(std::move(ptr)); } return boost::none; } template inline bool operator==(const unique_ref& lhs, const unique_ref& rhs) { return lhs.get() == rhs.get(); } template inline bool operator!=(const unique_ref& lhs, const unique_ref& rhs) { return !operator==(lhs, rhs); } template inline bool operator<(const unique_ref& lhs, const unique_ref& rhs) { return lhs.get() < rhs.get(); } template inline bool operator<=(const unique_ref& lhs, const unique_ref& rhs) { return !operator<(rhs, lhs); } template inline bool operator>(const unique_ref& lhs, const unique_ref& rhs) { return operator<(rhs, lhs); } template inline bool operator>=(const unique_ref& lhs, const unique_ref& rhs) { return !operator<(lhs, rhs); } } namespace std { template inline void swap(cpputils::unique_ref& lhs, cpputils::unique_ref& rhs) { lhs.swap(rhs); } template inline void swap(cpputils::unique_ref&& lhs, cpputils::unique_ref& rhs) { lhs.swap(rhs); } template inline void swap(cpputils::unique_ref& lhs, cpputils::unique_ref&& rhs) { lhs.swap(rhs); } } #endif