Molmodel
|
00001 /* GrinPointer.h */ 00002 00003 /* Portions copyright (c) 2007 Stanford University and Christopher M. Bruns. 00004 * Contributors: 00005 * 00006 * Permission is hereby granted, free of charge, to any person obtaining 00007 * a copy of this software and associated documentation files (the 00008 * "Software"), to deal in the Software without restriction, including 00009 * without limitation the rights to use, copy, modify, merge, publish, 00010 * distribute, sublicense, and/or sell copies of the Software, and to 00011 * permit persons to whom the Software is furnished to do so, subject 00012 * to the following conditions: 00013 * 00014 * The above copyright notice and this permission notice shall be included 00015 * in all copies or substantial portions of the Software. 00016 * 00017 * THE SOFTWARE IS PROVIdED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 00018 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 00019 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 00020 * IN NO EVENT SHALL THE AUTHORS, CONTRIBUTORS OR COPYRIGHT HOLDERS BE 00021 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 00022 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 00023 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 00024 */ 00025 00026 #ifndef SimTK_QUALIFIEDSMARTPOINTER_H_ 00027 #define SimTK_QUALIFIEDSMARTPOINTER_H_ 00028 00029 #include "Clonable.h" 00030 00031 // Templated class that uses semantics of a pointer. 00032 // Used as a helper class in the "Cheshire Cat", or PIMPL, 00033 // paradigm used to separate interface from implementation in 00034 // C++. 00035 00036 // Very similar to grin_ptr<> class by Alan Griffiths 00037 // http://www.octopull.demon.co.uk/arglib/TheGrin.html 00038 00039 // Uses concept of qualified smart pointer from 00040 // Kevlin Henney ("Coping with Copying in C++" - Overload 33 ISSN 1354 3172) 00041 00042 // "Qualified" means that the access operators, operator* and 00043 // operator->, are overloaded with respect to const-ness, so 00044 // their results follow the const qualification. 00045 00046 // From Alan Griffiths' article: 00047 // http://accu.org/index.php/journals/482 00048 // 00049 // "Let us start with the last point mentioned in the discussion of auto_ptr<> 00050 // - how to cope with deleting an incomplete type. The destructor can't be a 00051 // simple "delete p;" because at the point of instantiation the pointer is to 00052 // an "incomplete type" and the compiler won't call the destructor. 00053 // 00054 // To avoid this I make use of the fact that the constructor for grin_ptr<> 00055 // is instantiated in the implementation file, where the class definition for 00056 // implementation resides. At this point I force the compiler to generate a 00057 // deletion function using a trick I first saw in Richard Hickey's article 00058 // "Callbacks in C++ Using Template Functors" (C ++ Gems ISBN 1 884842 37 2): 00059 // the constructor stores a pointer to this function in the grin_ptr<>. This 00060 // provides a safe method for the destructor to delete the object it owns. 00061 // The point of passing around function pointers instead of the apparently 00062 // more natural use of virtual member functions is that everything can be 00063 // done "by value" and no dynamic allocation is required. 00064 // 00065 // A similar function is used for copying the object..." 00066 00067 namespace SimTK { 00068 00069 // Overloaded deepCopy() methods will use "clone()" method if 00070 // referent is derived from Clonable. Otherwise it calls new 00071 // with its copy constructor, which should work for non-derived 00072 // classes 00073 00074 // Fallback deep copy for non-Clonable objects 00075 template<class PointeeType> 00076 inline PointeeType* deepCopy(const PointeeType* ptr, const void*) 00077 { 00078 return ptr ? new PointeeType(*ptr) : 0; 00079 } 00080 00081 // Deep copy for objects that derive from Clonable 00082 template<class PointeeType> 00083 inline PointeeType* deepCopy(const PointeeType *ptr, const Clonable *) 00084 { 00085 return ptr ? ptr->clone() : 0; 00086 } 00087 00088 // At instantiation time, this method will decide which of the above to use. 00089 template<class PointeeType> 00090 inline PointeeType* deepCopy(const PointeeType* ptr) 00091 { 00092 return deepCopy(ptr, ptr); 00093 } 00094 00095 00096 template<typename PointeeType> 00097 class GrinPointer { 00098 public: 00099 explicit GrinPointer(PointeeType* pointee) 00100 : doCopy(&myCopyFunction), ptr(pointee), doDelete(&myDeleteFunction) 00101 { 00102 // doCopy = &myCopyFunction; 00103 // ptr = pointee; 00104 // doDelete = &myDeleteFunction; 00105 } 00106 00107 GrinPointer(const GrinPointer & src); 00108 00109 ~GrinPointer() throw() { doDelete(ptr); } 00110 00111 const PointeeType* operator->() const {return ptr;} 00112 PointeeType* operator->() {return ptr;} 00113 00114 const PointeeType& operator*() const {return *ptr;} 00115 PointeeType& operator*() {return *ptr;} 00116 00117 GrinPointer& operator=(const GrinPointer& src); 00118 00119 private: 00120 typedef void (*DeleteFunctionPtr)(PointeeType* ptr); 00121 typedef PointeeType* (*CopyFunctionPtr)(const PointeeType* ptr); 00122 00123 CopyFunctionPtr doCopy; 00124 PointeeType* ptr; 00125 DeleteFunctionPtr doDelete; 00126 00127 static void myDeleteFunction(PointeeType* ptr) { 00128 delete ptr; 00129 } 00130 static PointeeType* myCopyFunction(const PointeeType* ptr) { 00131 return deepCopy(ptr); 00132 } 00133 00134 }; 00135 00136 // Deep copy uses clone() method if wrapped type inherits the 00137 // "Clonable" interface. 00138 00139 template<typename PointeeType> 00140 inline GrinPointer<PointeeType>::GrinPointer(const GrinPointer& src) 00141 : 00142 doCopy(src.doCopy), 00143 ptr(doCopy(src.ptr)), 00144 doDelete(src.doDelete) 00145 {} 00146 00147 template<typename PointeeType> 00148 inline GrinPointer<PointeeType>& GrinPointer<PointeeType>::operator=(const GrinPointer& src) 00149 { 00150 // Allocate... 00151 PointeeType* tmp = doCopy(src.ptr); 00152 00153 // ...before release... 00154 doDelete(ptr); 00155 00156 // ...and update 00157 ptr = tmp; 00158 return *this; 00159 } 00160 00161 } 00162 00163 #endif // SimTK_QUALIFIEDSMARTPOINTER_H_