From ec3bec07ff001fbff98818a9842fa26520067954 Mon Sep 17 00:00:00 2001 From: Sebastian Messmer Date: Mon, 10 Apr 2017 15:14:02 -0700 Subject: [PATCH] Assert that unique_ref is always defined and not nullptr --- src/cpp-utils/pointer/unique_ref.h | 50 ++++++++++++++++++------------ 1 file changed, 31 insertions(+), 19 deletions(-) diff --git a/src/cpp-utils/pointer/unique_ref.h b/src/cpp-utils/pointer/unique_ref.h index 5956c1f6..6f626416 100644 --- a/src/cpp-utils/pointer/unique_ref.h +++ b/src/cpp-utils/pointer/unique_ref.h @@ -28,37 +28,42 @@ namespace cpputils { template> class unique_ref final { public: - // TODO Add assert != nullptr to all calls (also move constructors, ...) and test performance impact (maybe disable assertions in prod?) using element_type = typename std::unique_ptr::element_type; using deleter_type = typename std::unique_ptr::deleter_type; using pointer = typename std::unique_ptr::pointer; - unique_ref(unique_ref&& from) noexcept: _target(std::move(from._target)) { + unique_ref(unique_ref&& from) noexcept + : _target(std::move(from._target)) { from._target = nullptr; + _invariant(); } - template unique_ref(unique_ref&& from) noexcept: _target(std::move(from._target)) { + template unique_ref(unique_ref&& from) noexcept + : _target(std::move(from._target)) { from._target = nullptr; + _invariant(); } unique_ref& operator=(unique_ref&& from) noexcept { _target = std::move(from._target); from._target = nullptr; + _invariant(); return *this; } template unique_ref& operator=(unique_ref&& from) noexcept { _target = std::move(from._target); from._target = nullptr; + _invariant(); return *this; } typename std::add_lvalue_reference::type operator*() const& noexcept { - ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid."); + _invariant(); return *_target; } typename std::add_rvalue_reference::type operator*() && noexcept { - ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid."); + _invariant(); return std::move(*_target); } @@ -67,18 +72,20 @@ public: } pointer get() const noexcept { - ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid."); + _invariant(); return _target.get(); } template operator std::unique_ptr() && noexcept { - return std::move(_target); + _invariant(); + return std::move(_target); } template operator std::shared_ptr() && noexcept { - return std::move(_target); + _invariant(); + return std::move(_target); } void swap(unique_ref& rhs) noexcept { @@ -90,20 +97,29 @@ public: } deleter_type& get_deleter() noexcept { - return _target.get_deleter(); + return _target.get_deleter(); } const deleter_type& get_deleter() const noexcept { - return _target.get_deleter(); + return _target.get_deleter(); } private: - explicit unique_ref(std::unique_ptr target) noexcept: _target(std::move(target)) {} + explicit unique_ref(std::unique_ptr target) noexcept + : _target(std::move(target)) {} + + void _invariant() const { + // TODO Test performance impact of this + ASSERT(_target.get() != nullptr, "Member was moved out to another unique_ref. This instance is invalid."); + } + template friend unique_ref make_unique_ref(Args&&... args); template friend boost::optional> nullcheck(std::unique_ptr ptr) noexcept; template friend class unique_ref; template friend boost::optional> dynamic_pointer_move(unique_ref &source) noexcept; - template friend const typename unique_ref::pointer _extract_ptr(const unique_ref &obj) noexcept; + template friend bool operator==(const unique_ref& lhs, const unique_ref& rhs) noexcept; + friend struct std::hash>; + friend struct std::less>; std::unique_ptr _target; @@ -127,10 +143,6 @@ template inline void destruct(unique_ref /*ptr*/) { // ptr will be moved in to this function and destructed on return } -template const typename unique_ref::pointer _extract_ptr(const unique_ref &obj) noexcept { - return obj._target.get(); -} - //TODO Also allow passing a rvalue reference, otherwise dynamic_pointer_move(func()) won't work template inline boost::optional> dynamic_pointer_move(unique_ref &source) noexcept { @@ -139,7 +151,7 @@ inline boost::optional> dynamic_pointer_move(unique_ref &so template inline bool operator==(const unique_ref &lhs, const unique_ref &rhs) noexcept { - return _extract_ptr(lhs) == _extract_ptr(rhs); + return lhs._target == rhs._target; } template @@ -168,14 +180,14 @@ namespace std { // Allow using it in std::unordered_set / std::unordered_map template struct hash> { size_t operator()(const cpputils::unique_ref &ref) const noexcept { - return std::hash::pointer>()(_extract_ptr(ref)); + return std::hash>()(ref._target); } }; // Allow using it in std::map / std::set template struct less> { bool operator()(const cpputils::unique_ref &lhs, const cpputils::unique_ref &rhs) const noexcept { - return _extract_ptr(lhs) < _extract_ptr(rhs); + return lhs._target < rhs._target; } }; }