Skip to content

Instantly share code, notes, and snippets.

@alecthomas
Created September 3, 2013 15:49
Show Gist options
  • Save alecthomas/6425712 to your computer and use it in GitHub Desktop.
Save alecthomas/6425712 to your computer and use it in GitHub Desktop.
Weak pointer support for boost::intrusive_ptr
#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