In my opinion weak_ptr is one of the best parts about shared_ptr.
I didn't want to start adding shared_ptr's in but didn't want to have some insane management going on either so I whipped together this invasive guy so I could get
loose_ptr<T> from anyone who inherits from
enable_loose_ptr.
Then my manager just had to to periodically prune the ones that had gone bad while it was checking to see if it still cared about the good ones.
So I thought I'd share. If you read up on weak_ptr and enabled_shared_from_this<T> you should be able to get how it works pretty easily (unlike weak_ptr this will work with variables on the stack too).
Code:
#pragma once
// Copyright (C) 2011 - Jonathan Sandusky
// MIT License - read it here http://www.opensource.org/licenses/mit-license.php
//
// an invasive pointer that gets reset when the target object is destroyed
// (polymorphism is not supported here)
//
template<class TYPE> class loose_ptr {
loose_ptr<TYPE>& operator=(int); // prevent "obj=0;" because it doesn't work right
private:
TYPE* ptr_;
loose_ptr* next_;
public:
// default constructor
loose_ptr() : ptr_(0), next_(0) {}
// construct from dumb pointer
loose_ptr(TYPE* p) : ptr_(0), next_(0) {set(p);}
// construct from derived class dumb pointer
template<class T> loose_ptr(T* p) : ptr_(0), next_(0) {set(p);}
// construct from smart_ptr, shared_ptr, etc.
template<class T> loose_ptr(const T& t) : ptr_(0), next_(0) {set(t.get());}
// copy constructor (specialization of above)
loose_ptr(const loose_ptr& rhs) : ptr_(0), next_(0) {set(rhs.ptr_);}
// destructor
~loose_ptr() {set(0);}
TYPE* ptr() const {return ptr_;}
TYPE* get() const {return ptr_;}
TYPE* operator->() const {assert(ptr_); return ptr_;}
TYPE& operator*() const {assert(ptr_); return *ptr_;}
bool operator==(TYPE* p) const {return p == ptr_;}
bool operator!=(TYPE* p) const {return p != ptr_;}
bool expired() const {return !ptr_;}
class incomplete_class;
operator const incomplete_class*() const {return (const incomplete_class*)ptr_;}
// assign from dumb pointer
loose_ptr& operator=(TYPE* p) {set(p); return *this;}
// assign from smart_ptr, shared_ptr, etc.
template<class T> loose_ptr& operator=(const T& t) {set(t.get()); return *this;}
// assignment operator (specialization of above)
loose_ptr& operator=(const loose_ptr& rhs) {set(rhs.ptr_); return *this;}
void reset(TYPE* aPtr = 0) {set(aPtr);}
void set(TYPE* aPtr)
{
if (aPtr != ptr_) {
const enable_loose_ptr<TYPE>* ptr = ptr_;
if (ptr != 0) {
if (ptr->loose_ptr_head_ == this) {
ptr->loose_ptr_head_ = next_;
} else {
loose_ptr* prev = 0;
for (loose_ptr* p = ptr->loose_ptr_head_; p && p != this; prev = p, p = p->next_);
assert(prev && prev->next_ == this);
if (prev && prev->next_ == this)
prev->next_ = next_;
}
next_ = 0;
}
ptr = ptr_ = aPtr;
if (ptr_) {
next_ = ptr->loose_ptr_head_;
ptr->loose_ptr_head_ = this;
}
}
}
};
//
// required base class for objects that can have loose pointers to them
//
template<class TYPE> class enable_loose_ptr {
public:
// default constructor
enable_loose_ptr() : loose_ptr_head_(0)
{
}
// copy constructor
enable_loose_ptr(const enable_loose_ptr&) : loose_ptr_head_(0)
{
}
// destructor
~enable_loose_ptr()
{
while (loose_ptr_head_)
loose_ptr_head_->set(0);
}
// assignment operator
enable_loose_ptr& operator=(const enable_loose_ptr&)
{
}
private:
friend class loose_ptr<TYPE>;
mutable loose_ptr<TYPE>* loose_ptr_head_;
};