Created
September 3, 2013 15:49
-
-
Save alecthomas/6425712 to your computer and use it in GitHub Desktop.
Weak pointer support for boost::intrusive_ptr
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
#pragma once | |
#include <boost/intrusive_ptr.hpp> | |
using boost::intrusive_ptr; | |
struct _GC { | |
_GC() : references__(0), weak_references__(0) {} | |
virtual ~_GC() { | |
assert(references__ == 0 && weak_references__ == 0); | |
} | |
private: | |
friend void intrusive_ptr_add_ref(_GC *c); | |
friend void intrusive_ptr_release(_GC *c); | |
friend int use_count(const _GC *c); | |
template <typename T> friend class weak_intrusive_ptr; | |
int references__; | |
int weak_references__; | |
}; | |
/// Return number of references to a pointer. | |
inline int use_count(const _GC *c) { | |
return c->references__; | |
} | |
template <typename T> | |
class weak_intrusive_ptr { | |
public: | |
weak_intrusive_ptr(const intrusive_ptr<T> &ptr) : ptr_(ptr.get()) { // NOLINT | |
ptr_->weak_references__++; | |
} | |
weak_intrusive_ptr(const weak_intrusive_ptr &other) : ptr_(other.ptr_) { | |
ptr_->weak_references__++; | |
} | |
template <typename Y> | |
weak_intrusive_ptr(const intrusive_ptr<Y> &ptr) : ptr_(ptr.get()) { // NOLINT | |
ptr_->weak_references__++; | |
} | |
template <typename Y> | |
weak_intrusive_ptr(const weak_intrusive_ptr<Y> &ptr) : ptr_(ptr.ptr_) { // NOLINT | |
ptr_->weak_references__++; | |
} | |
weak_intrusive_ptr &operator = (const weak_intrusive_ptr &other) { | |
deref(); | |
ptr_ = other.ptr_; | |
ptr_->weak_references__++; | |
} | |
template <typename Y> | |
weak_intrusive_ptr &operator = (const weak_intrusive_ptr<Y> &other) { | |
deref(); | |
ptr_ = other.ptr_; | |
ptr_->weak_references__++; | |
} | |
// Move constructor. | |
weak_intrusive_ptr(weak_intrusive_ptr &&other) : ptr_(other.ptr_) { | |
other.ptr_ = nullptr; | |
} | |
weak_intrusive_ptr &operator = (weak_intrusive_ptr &&other) { | |
deref(); | |
ptr_ = other.ptr_; | |
other.ptr_ = nullptr; | |
} | |
template <typename Y> | |
weak_intrusive_ptr &operator = (weak_intrusive_ptr<Y> &&other) { | |
deref(); | |
ptr_ = other.ptr_; | |
other.ptr_ = nullptr; | |
} | |
~weak_intrusive_ptr() { deref(); } | |
intrusive_ptr<T> lock() const { | |
if (ptr_ && ptr_->references__) | |
return intrusive_ptr<T>(ptr_); | |
return intrusive_ptr<T>(); | |
} | |
bool expired() const { | |
return ptr_ && ptr_->references__ == 0; | |
} | |
private: | |
void deref() { | |
if (ptr_ && --ptr_->weak_references__ <= 0 && ptr_->references__ == 0) { | |
delete ptr_; | |
ptr_ = nullptr; | |
} | |
} | |
T *ptr_; | |
}; | |
/** | |
* An intrusive_ptr base class. | |
* | |
* Also supports weak references, though it's a bit suboptimal in that the | |
* referenced object will remain until all normal references and all weak | |
* references have expired. | |
* | |
* Use by subclassing GC: | |
* | |
* class MyClass : public GC { | |
* }; | |
* | |
* weak_intrusive_ptr<MyClass> weak; | |
* { | |
* intrusive_ptr<MyClass> a(new MyClass()); | |
* weak = a; | |
* } | |
* assert(weak.expired()); | |
*/ | |
struct GC : virtual public _GC {}; | |
inline void intrusive_ptr_add_ref(_GC *c) { | |
++c->references__; | |
} | |
inline void intrusive_ptr_release(_GC *c) { | |
if (--c->references__ == 0 && c->weak_references__ == 0) | |
delete c; | |
} | |
} // namespace entityx |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment