00001 // -*- c++ -*- 00002 #ifndef _cairo_REFPTR_H 00003 #define _cairo_REFPTR_H 00004 00005 /* $Id: refptr.h,v 1.1 2005/12/20 09:17:53 murrayc Exp $ */ 00006 00007 /* Copyright 2005 The cairomm Development Team 00008 * 00009 * This library is free software; you can redistribute it and/or 00010 * modify it under the terms of the GNU Library General Public 00011 * License as published by the Free Software Foundation; either 00012 * version 2 of the License, or (at your option) any later version. 00013 * 00014 * This library is distributed in the hope that it will be useful, 00015 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00017 * Library General Public License for more details. 00018 * 00019 * You should have received a copy of the GNU Library General Public 00020 * License along with this library; if not, write to the Free 00021 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00022 */ 00023 00024 00025 namespace Cairo 00026 { 00027 00045 template <class T_CppObject> 00046 class RefPtr 00047 { 00048 public: 00053 inline RefPtr(); 00054 00056 inline ~RefPtr(); 00057 00059 explicit inline RefPtr(T_CppObject* pCppObject); 00060 00065 inline RefPtr(const RefPtr<T_CppObject>& src); 00066 00071 template <class T_CastFrom> 00072 inline RefPtr(const RefPtr<T_CastFrom>& src); 00073 00079 inline void swap(RefPtr<T_CppObject>& other); 00080 00082 inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CppObject>& src); 00083 00088 template <class T_CastFrom> 00089 inline RefPtr<T_CppObject>& operator=(const RefPtr<T_CastFrom>& src); 00090 00092 inline bool operator==(const RefPtr<T_CppObject>& src) const; 00093 00095 inline bool operator!=(const RefPtr<T_CppObject>& src) const; 00096 00102 inline T_CppObject* operator->() const; 00103 00112 inline operator bool() const; 00113 00115 inline void clear(); 00116 00117 00125 template <class T_CastFrom> 00126 static inline RefPtr<T_CppObject> cast_dynamic(const RefPtr<T_CastFrom>& src); 00127 00135 template <class T_CastFrom> 00136 static inline RefPtr<T_CppObject> cast_static(const RefPtr<T_CastFrom>& src); 00137 00145 template <class T_CastFrom> 00146 static inline RefPtr<T_CppObject> cast_const(const RefPtr<T_CastFrom>& src); 00147 00148 private: 00149 T_CppObject* pCppObject_; 00150 }; 00151 00152 00153 #ifndef DOXYGEN_SHOULD_SKIP_THIS 00154 00155 // RefPtr<>::operator->() comes first here since it's used by other methods. 00156 // If it would come after them it wouldn't be inlined. 00157 00158 template <class T_CppObject> inline 00159 T_CppObject* RefPtr<T_CppObject>::operator->() const 00160 { 00161 return pCppObject_; 00162 } 00163 00164 template <class T_CppObject> inline 00165 RefPtr<T_CppObject>::RefPtr() 00166 : 00167 pCppObject_ (0) 00168 {} 00169 00170 template <class T_CppObject> inline 00171 RefPtr<T_CppObject>::~RefPtr() 00172 { 00173 if(pCppObject_) 00174 pCppObject_->unreference(); // This could cause pCppObject to be deleted. 00175 } 00176 00177 template <class T_CppObject> inline 00178 RefPtr<T_CppObject>::RefPtr(T_CppObject* pCppObject) 00179 : 00180 pCppObject_ (pCppObject) 00181 {} 00182 00183 template <class T_CppObject> inline 00184 RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CppObject>& src) 00185 : 00186 pCppObject_ (src.pCppObject_) 00187 { 00188 if(pCppObject_) 00189 pCppObject_->reference(); 00190 } 00191 00192 // The templated ctor allows copy construction from any object that's 00193 // castable. Thus, it does downcasts: 00194 // base_ref = derived_ref 00195 template <class T_CppObject> 00196 template <class T_CastFrom> 00197 inline 00198 RefPtr<T_CppObject>::RefPtr(const RefPtr<T_CastFrom>& src) 00199 : 00200 // A different RefPtr<> will not allow us access to pCppObject_. We need 00201 // to add a get_underlying() for this, but that would encourage incorrect 00202 // use, so we use the less well-known operator->() accessor: 00203 pCppObject_ (src.operator->()) 00204 { 00205 if(pCppObject_) 00206 pCppObject_->reference(); 00207 } 00208 00209 template <class T_CppObject> inline 00210 void RefPtr<T_CppObject>::swap(RefPtr<T_CppObject>& other) 00211 { 00212 T_CppObject *const temp = pCppObject_; 00213 pCppObject_ = other.pCppObject_; 00214 other.pCppObject_ = temp; 00215 } 00216 00217 template <class T_CppObject> inline 00218 RefPtr<T_CppObject>& RefPtr<T_CppObject>::operator=(const RefPtr<T_CppObject>& src) 00219 { 00220 // In case you haven't seen the swap() technique to implement copy 00221 // assignment before, here's what it does: 00222 // 00223 // 1) Create a temporary RefPtr<> instance via the copy ctor, thereby 00224 // increasing the reference count of the source object. 00225 // 00226 // 2) Swap the internal object pointers of *this and the temporary 00227 // RefPtr<>. After this step, *this already contains the new pointer, 00228 // and the old pointer is now managed by temp. 00229 // 00230 // 3) The destructor of temp is executed, thereby unreferencing the 00231 // old object pointer. 00232 // 00233 // This technique is described in Herb Sutter's "Exceptional C++", and 00234 // has a number of advantages over conventional approaches: 00235 // 00236 // - Code reuse by calling the copy ctor. 00237 // - Strong exception safety for free. 00238 // - Self assignment is handled implicitely. 00239 // - Simplicity. 00240 // - It just works and is hard to get wrong; i.e. you can use it without 00241 // even thinking about it to implement copy assignment whereever the 00242 // object data is managed indirectly via a pointer, which is very common. 00243 00244 RefPtr<T_CppObject> temp (src); 00245 this->swap(temp); 00246 return *this; 00247 } 00248 00249 template <class T_CppObject> 00250 template <class T_CastFrom> 00251 inline 00252 RefPtr<T_CppObject>& RefPtr<T_CppObject>::operator=(const RefPtr<T_CastFrom>& src) 00253 { 00254 RefPtr<T_CppObject> temp (src); 00255 this->swap(temp); 00256 return *this; 00257 } 00258 00259 template <class T_CppObject> inline 00260 bool RefPtr<T_CppObject>::operator==(const RefPtr<T_CppObject>& src) const 00261 { 00262 return (pCppObject_ == src.pCppObject_); 00263 } 00264 00265 template <class T_CppObject> inline 00266 bool RefPtr<T_CppObject>::operator!=(const RefPtr<T_CppObject>& src) const 00267 { 00268 return (pCppObject_ != src.pCppObject_); 00269 } 00270 00271 template <class T_CppObject> inline 00272 RefPtr<T_CppObject>::operator bool() const 00273 { 00274 return (pCppObject_ != 0); 00275 } 00276 00277 template <class T_CppObject> inline 00278 void RefPtr<T_CppObject>::clear() 00279 { 00280 RefPtr<T_CppObject> temp; // swap with an empty RefPtr<> to clear *this 00281 this->swap(temp); 00282 } 00283 00284 template <class T_CppObject> 00285 template <class T_CastFrom> 00286 inline 00287 RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_dynamic(const RefPtr<T_CastFrom>& src) 00288 { 00289 T_CppObject *const pCppObject = dynamic_cast<T_CppObject*>(src.operator->()); 00290 00291 if(pCppObject) 00292 pCppObject->reference(); 00293 00294 return RefPtr<T_CppObject>(pCppObject); 00295 } 00296 00297 template <class T_CppObject> 00298 template <class T_CastFrom> 00299 inline 00300 RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_static(const RefPtr<T_CastFrom>& src) 00301 { 00302 T_CppObject *const pCppObject = static_cast<T_CppObject*>(src.operator->()); 00303 00304 if(pCppObject) 00305 pCppObject->reference(); 00306 00307 return RefPtr<T_CppObject>(pCppObject); 00308 } 00309 00310 template <class T_CppObject> 00311 template <class T_CastFrom> 00312 inline 00313 RefPtr<T_CppObject> RefPtr<T_CppObject>::cast_const(const RefPtr<T_CastFrom>& src) 00314 { 00315 T_CppObject *const pCppObject = const_cast<T_CppObject*>(src.operator->()); 00316 00317 if(pCppObject) 00318 pCppObject->reference(); 00319 00320 return RefPtr<T_CppObject>(pCppObject); 00321 } 00322 00323 #endif /* DOXYGEN_SHOULD_SKIP_THIS */ 00324 00326 template <class T_CppObject> inline 00327 void swap(RefPtr<T_CppObject>& lhs, RefPtr<T_CppObject>& rhs) 00328 { 00329 lhs.swap(rhs); 00330 } 00331 00332 } // namespace Cairo 00333 00334 00335 #endif /* _cairo_REFPTR_H */ 00336