Created
May 30, 2018 22:16
-
-
Save qrealka/c84413c75b368b886fb64ecf635e5786 to your computer and use it in GitHub Desktop.
intrusive pointer
This file contains 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 characters
template<class T> | |
class intrusive_ptr { | |
public: | |
using pointer = T*; | |
using const_pointer = const T*; | |
using element_type = T; | |
using reference = T&; | |
using const_reference = const T&; | |
constexpr intrusive_ptr() noexcept : ptr_(nullptr) {} | |
// todo: should be template. as all ctors | |
intrusive_ptr(pointer raw_ptr, bool add_ref = true) noexcept { | |
set_ptr(raw_ptr, add_ref); | |
} | |
intrusive_ptr(intrusive_ptr &&other) noexcept : ptr_(other.detach()) {} | |
intrusive_ptr(const intrusive_ptr &other) noexcept { | |
set_ptr(other.get(), true); | |
} | |
template<class Y> | |
intrusive_ptr(intrusive_ptr<Y> other) : ptr_(other.detach()) { | |
static_assert(std::is_convertible<Y *, T *>::value, | |
"Y* is not assignable to T*"); | |
} | |
intrusive_ptr &operator=(pointer ptr) noexcept { | |
reset(ptr); | |
return *this; | |
} | |
intrusive_ptr &operator=(intrusive_ptr other) noexcept { | |
swap(other); | |
return *this; | |
} | |
~intrusive_ptr() { | |
if (ptr_) { | |
intrusive_ptr_release(*ptr_); | |
} | |
} | |
pointer detach() noexcept { | |
auto result = ptr_; | |
if (result) { | |
ptr_ = nullptr; | |
} | |
return result; | |
} | |
pointer release() noexcept { | |
return detach(); | |
} | |
void reset(pointer new_value = nullptr, bool add_ref = true) noexcept { | |
auto old = ptr_; | |
set_ptr(new_value, add_ref); | |
if (old) { | |
intrusive_ptr_release(*old); | |
} | |
} | |
pointer get() const noexcept { | |
return ptr_; | |
} | |
pointer operator->() const noexcept { | |
return ptr_; | |
} | |
reference operator*() const { | |
return *ptr_; | |
} | |
explicit operator bool() const noexcept { | |
return ptr_ != nullptr; | |
} | |
void swap(intrusive_ptr &other) noexcept { | |
std::swap(ptr_, other.ptr_); | |
} | |
template<class C> | |
intrusive_ptr<C> down_pointer_cast() const noexcept { | |
return (ptr_) ? dynamic_cast<C *>(get()) : nullptr; | |
} | |
template<class C> | |
intrusive_ptr<C> up_pointer_cast() const noexcept { | |
return (ptr_) ? static_cast<C *>(get()) : nullptr; | |
} | |
private: | |
inline void set_ptr(pointer raw_ptr, bool add_ref) noexcept { | |
ptr_ = raw_ptr; | |
if (raw_ptr && add_ref) { | |
intrusive_ptr_add_ref(*raw_ptr); | |
} | |
} | |
pointer ptr_; | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment