1 #ifndef INTRUSIVE_PTR_H
2 #define INTRUSIVE_PTR_H
9 #include "opthelpers.h"
16 std::atomic
<unsigned int> mRef
{1u};
19 unsigned int add_ref() noexcept
{ return IncrementRef(mRef
); }
20 unsigned int dec_ref() noexcept
22 auto ref
= DecrementRef(mRef
);
24 delete static_cast<T
*>(this);
29 * Release only if doing so would not bring the object to 0 references and
30 * delete it. Returns false if the object could not be released.
32 * NOTE: The caller is responsible for handling a failed release, as it
33 * means the object has no other references and needs to be be deleted
36 bool releaseIfNoDelete() noexcept
38 auto val
= mRef
.load(std::memory_order_acquire
);
39 while(val
> 1 && !mRef
.compare_exchange_strong(val
, val
-1, std::memory_order_acq_rel
))
41 /* val was updated with the current value on failure, so just try
56 intrusive_ptr() noexcept
= default;
57 intrusive_ptr(const intrusive_ptr
&rhs
) noexcept
: mPtr
{rhs
.mPtr
}
58 { if(mPtr
) mPtr
->add_ref(); }
59 intrusive_ptr(intrusive_ptr
&& rhs
) noexcept
: mPtr
{rhs
.mPtr
}
60 { rhs
.mPtr
= nullptr; }
61 intrusive_ptr(std::nullptr_t
) noexcept
{ }
62 explicit intrusive_ptr(T
*ptr
) noexcept
: mPtr
{ptr
} { }
63 ~intrusive_ptr() { if(mPtr
) mPtr
->dec_ref(); }
65 /* NOLINTBEGIN(bugprone-unhandled-self-assignment)
66 * Self-assignment is handled properly here.
68 intrusive_ptr
& operator=(const intrusive_ptr
&rhs
) noexcept
70 static_assert(noexcept(std::declval
<T
*>()->dec_ref()), "dec_ref must be noexcept");
72 if(rhs
.mPtr
) rhs
.mPtr
->add_ref();
73 if(mPtr
) mPtr
->dec_ref();
77 /* NOLINTEND(bugprone-unhandled-self-assignment) */
78 intrusive_ptr
& operator=(intrusive_ptr
&& rhs
) noexcept
80 if(&rhs
!= this) LIKELY
82 if(mPtr
) mPtr
->dec_ref();
83 mPtr
= std::exchange(rhs
.mPtr
, nullptr);
88 explicit operator bool() const noexcept
{ return mPtr
!= nullptr; }
90 [[nodiscard
]] auto operator*() const noexcept
-> T
& { return *mPtr
; }
91 [[nodiscard
]] auto operator->() const noexcept
-> T
* { return mPtr
; }
92 [[nodiscard
]] auto get() const noexcept
-> T
* { return mPtr
; }
94 void reset(T
*ptr
=nullptr) noexcept
101 T
* release() noexcept
{ return std::exchange(mPtr
, nullptr); }
103 void swap(intrusive_ptr
&rhs
) noexcept
{ std::swap(mPtr
, rhs
.mPtr
); }
104 void swap(intrusive_ptr
&& rhs
) noexcept
{ std::swap(mPtr
, rhs
.mPtr
); }
109 #endif /* INTRUSIVE_PTR_H */