From: ehofman Date: Thu, 29 Dec 2005 12:00:29 +0000 (+0000) Subject: Mathias Fröhlich: X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=8f9921d00c692573263a0215150e0892a9ffb68c;p=simgear.git Mathias Fröhlich: Add the basic infrastructure for a reference counter class. Adding it now (without using it) enables Mathias and others to prepare some memory reduction code. --- diff --git a/simgear/structure/Makefile.am b/simgear/structure/Makefile.am index 386c9d94..e7d361ae 100644 --- a/simgear/structure/Makefile.am +++ b/simgear/structure/Makefile.am @@ -7,7 +7,10 @@ include_HEADERS = \ commands.hxx \ exception.hxx \ event_mgr.hxx \ - subsystem_mgr.hxx + ssgSharedPtr.hxx \ + subsystem_mgr.hxx \ + SGReferenced.hxx \ + SGSharedPtr.hxx libsgstructure_a_SOURCES = \ commands.cxx \ diff --git a/simgear/structure/SGReferenced.hxx b/simgear/structure/SGReferenced.hxx new file mode 100644 index 00000000..003536a3 --- /dev/null +++ b/simgear/structure/SGReferenced.hxx @@ -0,0 +1,53 @@ +/* -*-c++-*- + * + * Copyright (C) 2005-2006 Mathias Froehlich + * + * 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 the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef SGReferenced_HXX +#define SGReferenced_HXX + +/// Base class for all reference counted SimGear objects +/// Classes derived from this one are meant to be managed with +/// the SGSharedPtr class. +/// For more info see @SGSharedPtr. + +class SGReferenced { +public: + SGReferenced(void) : _refcount(0u) + {} + /// Do not copy reference counts. Each new object has it's own counter + SGReferenced(const SGReferenced&) : _refcount(0u) + {} + /// Do not copy reference counts. Each object has it's own counter + SGReferenced& operator=(const SGReferenced&) + { return *this; } + + static unsigned get(const SGReferenced* ref) + { if (ref) return ++(ref->_refcount); else return ~0u; } + static unsigned put(const SGReferenced* ref) + { if (ref) return --(ref->_refcount); else return ~0u; } + static unsigned count(const SGReferenced* ref) + { if (ref) return ref->_refcount; else return ~0u; } + static bool shared(const SGReferenced* ref) + { if (ref) return 1u < ref->_refcount; else return false; } + +private: + mutable unsigned _refcount; +}; + +#endif diff --git a/simgear/structure/SGSharedPtr.hxx b/simgear/structure/SGSharedPtr.hxx new file mode 100644 index 00000000..6b7c09d2 --- /dev/null +++ b/simgear/structure/SGSharedPtr.hxx @@ -0,0 +1,99 @@ +/* -*-c++-*- + * + * Copyright (C) 2005-2006 Mathias Froehlich + * + * 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 the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef SGSharedPtr_HXX +#define SGSharedPtr_HXX + +#include "SGReferenced.hxx" + +/// This class is a pointer proxy doing reference counting on the object +/// it is pointing to. +/// The SGSharedPtr class handles reference counting and possible +/// destruction if no nore references are in use automatically. +/// Classes derived from @SGReferenced can be handled with SGSharedPtr. +/// Once you have a SGSharedPtr available you can use it just like +/// a usual pointer with the exception that you don't need to delete it. +/// Such a reference is initialized by zero if not initialized with a +/// class pointer. +/// One thing you need to avoid are cyclic loops with such pointers. +/// As long as such a cyclic loop exists the reference count never drops +/// to zero and consequently the objects will never be destroyed. +/// Always try to use directed graphs where the references away from the +/// top node are made with SGSharedPtr's and the back references are done with +/// ordinary pointers. +/// There is a very good description of OpenSceneGraphs ref_ptr which is +/// pretty much the same than this one at +/// http://dburns.dhs.org/OSG/Articles/RefPointers/RefPointers.html + +template +class SGSharedPtr { +public: + SGSharedPtr(void) : _ptr(0) + {} + SGSharedPtr(T* ptr) : _ptr(ptr) + { get(_ptr); } + SGSharedPtr(const SGSharedPtr& p) : _ptr(p.ptr()) + { get(_ptr); } + template + SGSharedPtr(const SGSharedPtr& p) : _ptr(p.ptr()) + { get(_ptr); } + ~SGSharedPtr(void) + { put(); } + + SGSharedPtr& operator=(const SGSharedPtr& p) + { assign(p.ptr()); return *this; } + template + SGSharedPtr& operator=(const SGSharedPtr& p) + { assign(p.ptr()); return *this; } + template + SGSharedPtr& operator=(U* p) + { assign(p); return *this; } + + T* operator->(void) const + { return _ptr; } + T& operator*(void) const + { return *_ptr; } + operator T*(void) const + { return _ptr; } + T* ptr(void) const + { return _ptr; } + + bool isShared(void) const + { return SGReferenced::shared(_ptr); } + unsigned getNumRefs(void) const + { return SGReferenced::count(_ptr); } + + bool valid(void) const + { return _ptr; } + +private: + void assign(T* p) + { get(p); put(); _ptr = p; } + + void get(const T* p) const + { SGReferenced::get(p); } + void put(void) + { if (!SGReferenced::put(_ptr)) { delete _ptr; _ptr = 0; } } + + // The reference itself. + T* _ptr; +}; + +#endif diff --git a/simgear/structure/ssgSharedPtr.hxx b/simgear/structure/ssgSharedPtr.hxx new file mode 100644 index 00000000..87dae7eb --- /dev/null +++ b/simgear/structure/ssgSharedPtr.hxx @@ -0,0 +1,94 @@ +/* -*-c++-*- + * + * Copyright (C) 2005-2006 Mathias Froehlich + * + * 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 the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * 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., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#ifndef ssgSharedPtr_HXX +#define ssgSharedPtr_HXX + +/// This class is a pointer proxy doing reference counting on the object +/// it is pointing to. +/// It is very similar to the SGSharedPtr class but is made to work together +/// with reference counting of plib's ssg reference counters +/// For notes on usage see SGSharedPtr. + +template +class ssgSharedPtr { +public: + ssgSharedPtr(void) : _ptr(0) + {} + ssgSharedPtr(T* ptr) : _ptr(ptr) + { get(_ptr); } + ssgSharedPtr(const ssgSharedPtr& p) : _ptr(p.ptr()) + { get(_ptr); } + template + ssgSharedPtr(const ssgSharedPtr& p) : _ptr(p.ptr()) + { get(_ptr); } + ~ssgSharedPtr(void) + { put(); } + + ssgSharedPtr& operator=(const ssgSharedPtr& p) + { assign(p.ptr()); return *this; } + template + ssgSharedPtr& operator=(const ssgSharedPtr& p) + { assign(p.ptr()); return *this; } + template + ssgSharedPtr& operator=(U* p) + { assign(p); return *this; } + + T* operator->(void) const + { return _ptr; } + T& operator*(void) const + { return *_ptr; } + operator T*(void) const + { return _ptr; } + T* ptr(void) const + { return _ptr; } + + bool isShared(void) const + { if (_ptr) return 1 < _ptr->getRef(); else return false; } + unsigned getNumRefs(void) const + { if (_ptr) return _ptr->getRef(); else return 0; } + + bool valid(void) const + { return _ptr; } + +private: + void assign(T* p) + { get(p); put(); _ptr = p; } + + static void get(T* p) + { if (p) p->ref(); } + void put(void) + { + if (!_ptr) + return; + + assert(0 < _ptr->getRef()); + _ptr->deRef(); + if (_ptr->getRef() == 0) { + delete _ptr; + _ptr = 0; + } + } + + // The reference itself. + T* _ptr; +}; + +#endif