X-Git-Url: https://www.ginac.de/ginac.git//ginac.git?p=ginac.git;a=blobdiff_plain;f=ginac%2Fptr.h;h=c8b0691230bc5c8d8b8c49fc7f7d63620a2387c9;hp=fd380506fdd6daaec5183e94f8557c7306f51f4c;hb=6ff92476a4dcd32f9a0c6f59c95c74812ea86fef;hpb=6eedac996204ebc3355807d7f887b0c366cb3c07 diff --git a/ginac/ptr.h b/ginac/ptr.h index fd380506..c8b06912 100644 --- a/ginac/ptr.h +++ b/ginac/ptr.h @@ -3,7 +3,7 @@ * Reference-counted pointer template. */ /* - * GiNaC Copyright (C) 1999-2003 Johannes Gutenberg University Mainz, Germany + * GiNaC Copyright (C) 1999-2008 Johannes Gutenberg University Mainz, Germany * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -17,12 +17,13 @@ * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #ifndef __GINAC_PTR_H__ #define __GINAC_PTR_H__ +#include // for size_t #include #include @@ -30,12 +31,28 @@ namespace GiNaC { + +/** Base class for reference-counted objects. */ +class refcounted { +public: + refcounted() throw() : refcount(0) {} + + size_t add_reference() throw() { return ++refcount; } + size_t remove_reference() throw() { return --refcount; } + size_t get_refcount() const throw() { return refcount; } + void set_refcount(size_t r) throw() { refcount = r; } + +private: + size_t refcount; ///< reference counter +}; + + /** Class of (intrusively) reference-counted pointers that support * copy-on-write semantics. * * Requirements for T: - * T::refcount member that supports ++refcount, --refcount, refcount = 1, - * refcount == 0 and refcount > 1 + * must support the refcounted interface (usually by being derived + * from refcounted) * T* T::duplicate() member function (only if makewriteable() is used) */ template class ptr { friend class std::less< ptr >; @@ -48,26 +65,29 @@ public: // no default ctor: a ptr is never unbound /** Bind ptr to newly created object, start reference counting. */ - ptr(T *t) throw() : p(t) { GINAC_ASSERT(p); p->refcount = 1; } + ptr(T *t) throw() : p(t) { GINAC_ASSERT(p); p->set_refcount(1); } /** Bind ptr to existing reference-counted object. */ - explicit ptr(T &t) throw() : p(&t) { ++p->refcount; } + explicit ptr(T &t) throw() : p(&t) { p->add_reference(); } - ptr(const ptr & other) throw() : p(other.p) { ++p->refcount; } + ptr(const ptr & other) throw() : p(other.p) { p->add_reference(); } ~ptr() { - if (--p->refcount == 0) + if (p->remove_reference() == 0) delete p; } ptr &operator=(const ptr & other) { - // NB: must first increment other.p->refcount, since other might be *this. - ++other.p->refcount; - if (--p->refcount == 0) + // NB1: Must first add reference to "other", since other might be *this. + // NB2: Cache other.p, because if "other" is a subexpression of p, + // deleting p will also invalidate "other". + T *otherp = other.p; + otherp->add_reference(); + if (p->remove_reference() == 0) delete p; - p = other.p; + p = otherp; return *this; } @@ -80,10 +100,10 @@ public: * This ensures that the object is not shared by any other ptrs. */ void makewritable() { - if (p->refcount > 1) { + if (p->get_refcount() > 1) { T *p2 = p->duplicate(); - p2->refcount = 1; - --p->refcount; + p2->set_refcount(1); + p->remove_reference(); p = p2; } } @@ -122,6 +142,7 @@ public: inline friend std::ostream & operator<<(std::ostream & os, const ptr & rhs) { os << rhs.p; + return os; } private: @@ -130,6 +151,7 @@ private: } // namespace GiNaC + namespace std { /** Specialization of std::less for ptr to enable ordering of ptr