]> git.tdb.fi Git - libs/core.git/commitdiff
RefPtr:
authorMikko Rasa <tdb@tdb.fi>
Fri, 8 Oct 2010 19:54:28 +0000 (19:54 +0000)
committerMikko Rasa <tdb@tdb.fi>
Fri, 8 Oct 2010 19:54:28 +0000 (19:54 +0000)
Add templated copy-ctor and copy-assignment
Add assignment from a plain pointer for efficiency
Add keep() method to prevent deletion of data
Fix a potential leak in cast_dynamic
Style updates

source/core/refptr.h

index dd07256d79d45ca1fa1ff558eacab32ca925ed79..ddada0b0b64ae92535c4d4a1c1160330fd6569b3 100644 (file)
@@ -1,7 +1,7 @@
 /* $Id$
 
 This file is part of libmspcore
-Copyright © 2006-2007 Mikko Rasa, Mikkosoft Productions
+Copyright © 2006-2007, 2010 Mikko Rasa, Mikkosoft Productions
 Distributed under the LGPL
 */
 
@@ -17,18 +17,35 @@ destroyed, the data is deleted as well.
 template<typename T>
 class RefPtr
 {
+private:
+       enum
+       {
+               KEEP = 1U<<(sizeof(unsigned)*8-1)
+       };
+
 public:
        RefPtr(): data(0), count(0) { }
-       RefPtr(T *d): data(d), count(0) { if(data) count=new unsigned(1); }
+       RefPtr(T *d): data(d), count(data ? new unsigned(1) : 0) { }
+
+       // Must have this or the compiler will generate a default copy-c'tor
        RefPtr(const RefPtr &p): data(p.data), count(p.count) { incref(); }
-       RefPtr &operator=(const RefPtr &p)
+
+       template<typename U>
+       RefPtr(const RefPtr<U> &p): data(p.data), count(p.count) { incref(); }
+
+       RefPtr &operator=(T *d)
        {
                decref();
-               data=p.data;
-               count=p.count;
-               incref();
+               data = d;
+               count = (d ? new unsigned(1) : 0);
                return *this;
        }
+
+       // Likewise for the assignment operator
+       RefPtr &operator=(const RefPtr &p) { return assign(p); }
+
+       template<typename U>
+       RefPtr &operator=(const RefPtr<U> &p) { return assign(p); }
        
        ~RefPtr() { decref(); }
 
@@ -39,34 +56,56 @@ public:
        */
        T *release()
        {
-               T *d=data;
-               data=0;
+               T *d = data;
+               data = 0;
                decref();
-               count=0;
+               count = 0;
                return d;
        }
 
-       T *get() const        { return data; }
-       T &operator*() const  { return *data; }
+       /**
+       Marks the data to not be deleted.  This affects all RefPtrs with the same
+       data.
+       */
+       void keep()
+       {
+               if(count)
+                       *count |= KEEP;
+       }
+
+       T *get() const { return data; }
+       T &operator*() const { return *data; }
        T *operator->() const { return data; }
        operator bool() const { return data!=0; }
 
        template<typename U>
-       static RefPtr<T> cast_dynamic(const RefPtr<U> &p)  { return RefPtr<T>(dynamic_cast<T *>(p.data), p.count); }
+       static RefPtr<T> cast_dynamic(const RefPtr<U> &p)
+       { return RefPtr<T>(dynamic_cast<T *>(p.data), p.count); }
+
        template<typename U> friend class RefPtr;
 private:
-       T        *data;
+       T *data;
        unsigned *count;
 
-       RefPtr(T *d, unsigned *c): data(d), count(c) { incref(); }
+       RefPtr(T *d, unsigned *c): data(d), count(d ? c : 0) { incref(); }
 
-       void  incref()
+       template<typename U>
+       RefPtr &assign(const RefPtr<U> &p)
+       {
+               decref();
+               data = p.data;
+               count = p.count;
+               incref();
+               return *this;
+       }
+
+       void incref()
        {
                if(!count) return;
                ++*count;
        }
 
-       void  decref()
+       void decref()
        {
                if(!count) return;
                --*count;
@@ -74,8 +113,14 @@ private:
                {
                        delete data;
                        delete count;
-                       data=0;
-                       count=0;
+                       data = 0;
+                       count = 0;
+               }
+               else if(*count==KEEP)
+               {
+                       delete count;
+                       data = 0;
+                       count = 0;
                }
        }
 };