Skip to content

Instantly share code, notes, and snippets.

@qrealka
Created May 30, 2018 22:16
Show Gist options
  • Save qrealka/c84413c75b368b886fb64ecf635e5786 to your computer and use it in GitHub Desktop.
Save qrealka/c84413c75b368b886fb64ecf635e5786 to your computer and use it in GitHub Desktop.
intrusive pointer
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