00001 // 00002 // aegis - project change supervisor 00003 // Copyright (C) 2007, 2008 Peter Miller 00004 // 00005 // This program is free software; you can redistribute it and/or modify 00006 // it under the terms of the GNU General Public License as published by 00007 // the Free Software Foundation; either version 3 of the License, or 00008 // (at your option) any later version. 00009 // 00010 // This program is distributed in the hope that it will be useful, 00011 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 // GNU General Public License for more details. 00014 // 00015 // You should have received a copy of the GNU General Public License 00016 // along with this program. If not, see 00017 // <http://www.gnu.org/licenses/>. 00018 // 00019 00020 #ifndef COMMON_AC_SHARED_PTR_AEGIS_H 00021 #define COMMON_AC_SHARED_PTR_AEGIS_H 00022 00023 #include <common/error.h> // for assert 00024 00035 template<class T> 00036 class aegis_shared_ptr 00037 { 00038 private: 00050 long *reference_count; 00051 00057 T *subject; 00058 00059 public: 00064 bool 00065 valid() 00066 const 00067 { 00068 return 00069 ( 00070 (reference_count != 0) 00071 ? 00072 (*reference_count > 0 && subject != 0) 00073 : 00074 (subject == 0) 00075 ); 00076 } 00077 00085 ~aegis_shared_ptr() 00086 { 00087 assert(valid()); 00088 if (reference_count) 00089 { 00090 --*reference_count; 00091 if (*reference_count <= 0) 00092 { 00093 delete subject; 00094 subject = 0; 00095 delete reference_count; 00096 reference_count = 0; 00097 } 00098 } 00099 } 00100 00107 void 00108 swap(aegis_shared_ptr &rhs) 00109 { 00110 assert(valid()); 00111 assert(rhs.valid()); 00112 long *temp_reference_count = reference_count; 00113 T *temp_subject = subject; 00114 reference_count = rhs.reference_count; 00115 subject = rhs.subject; 00116 rhs.reference_count = temp_reference_count; 00117 rhs.subject = temp_subject; 00118 } 00119 00123 void 00124 reset() 00125 { 00126 // swap with a NULL pointer 00127 aegis_shared_ptr tmp; 00128 this->swap(tmp); 00129 } 00130 00134 aegis_shared_ptr() : 00135 reference_count(0), 00136 subject(0) 00137 { 00138 assert(valid()); 00139 } 00140 00148 template<class Y> explicit 00149 aegis_shared_ptr(Y *rhs) : 00150 reference_count(0), 00151 subject(0) 00152 { 00153 assert(valid()); 00154 if (rhs) 00155 { 00156 reference_count = new long(1); 00157 subject = rhs; 00158 } 00159 assert(valid()); 00160 } 00161 00168 aegis_shared_ptr(const aegis_shared_ptr &rhs) : 00169 reference_count(0), 00170 subject(0) 00171 { 00172 assert(rhs.valid()); 00173 if (rhs.subject) 00174 { 00175 assert(rhs.reference_count); 00176 reference_count = rhs.reference_count; 00177 subject = rhs.subject; 00178 ++*reference_count; 00179 } 00180 assert(valid()); 00181 } 00182 00183 template <class Y> friend class aegis_shared_ptr; 00184 00191 template<class Y> 00192 aegis_shared_ptr(const aegis_shared_ptr<Y> &rhs) : 00193 reference_count(0), 00194 subject(0) 00195 { 00196 assert(rhs.valid()); 00197 if (rhs.subject) 00198 { 00199 assert(rhs.reference_count); 00200 reference_count = rhs.reference_count; 00201 subject = rhs.subject; 00202 ++*reference_count; 00203 } 00204 assert(valid()); 00205 } 00206 00213 aegis_shared_ptr & 00214 operator=(const aegis_shared_ptr &rhs) 00215 { 00216 assert(valid()); 00217 assert(rhs.valid()); 00218 if (this != &rhs) 00219 { 00220 // In case you haven't seen the swap() technique to 00221 // implement copy assignment before, here's what it does: 00222 // 00223 // 1) Create a temporary aegis_shared_ptr<> instance via the 00224 // copy constructor, thereby increasing the reference 00225 // count of the source object. 00226 // 00227 // 2) Swap the internal object pointers of *this and the 00228 // temporary aegis_shared_ptr<>. After this step, *this 00229 // already contains the new pointer, and the old pointer 00230 // is now managed by temp. 00231 // 00232 // 3) The destructor of temp is executed, thereby 00233 // unreferencing the old object pointer. 00234 // 00235 // This technique is described in Herb Sutter's "Exceptional 00236 // C++", and has a number of advantages over conventional 00237 // approaches: 00238 // 00239 // - Code reuse by calling the copy constructor. 00240 // - Strong exception safety for free. 00241 // - Self assignment is handled implicitly. 00242 // - Simplicity. 00243 // - It just works and is hard to get wrong; i.e. you can 00244 // use it without even thinking about it to implement 00245 // copy assignment where ever the object data is managed 00246 // indirectly via a pointer, which is very common. 00247 // 00248 aegis_shared_ptr temp(rhs); 00249 this->swap(temp); 00250 assert(valid()); 00251 assert(rhs.valid()); 00252 } 00253 return *this; 00254 } 00255 00262 template<class Y> 00263 aegis_shared_ptr & 00264 operator=(const aegis_shared_ptr<Y> &rhs) 00265 { 00266 assert(valid()); 00267 assert(rhs.valid()); 00268 if (this != (aegis_shared_ptr *)&rhs) 00269 { 00270 aegis_shared_ptr tmp(rhs); 00271 this->swap(tmp); 00272 assert(valid()); 00273 assert(rhs.valid()); 00274 } 00275 return *this; 00276 } 00277 00278 #if 0 00279 00285 template<class Y> explicit 00286 aegis_shared_ptr(std::auto_ptr<Y> &rhs) : 00287 reference_count(0), 00288 subject(0) 00289 { 00290 Y *tmp = r.get(); 00291 if (tmp) 00292 { 00293 reference_count = new long(1); 00294 subject = tmp; 00295 } 00296 assert(valid()); 00297 } 00298 00305 template<class Y> 00306 aegis_shared_ptr & 00307 operator=(std::auto_ptr<Y> &rhs) 00308 { 00309 assert(valid()); 00310 reset(); 00311 if (tmp) 00312 { 00313 reference_count = new long(1); 00314 subject = tmp; 00315 } 00316 assert(valid()); 00317 return *this; 00318 } 00319 00320 #endif 00321 00329 T & 00330 operator*() 00331 const 00332 { 00333 assert(subject != 0); 00334 return *subject; 00335 } 00336 00344 T * 00345 operator->() 00346 const 00347 { 00348 assert(subject != 0); 00349 return subject; 00350 } 00351 00355 T * 00356 get() 00357 const 00358 { 00359 return subject; 00360 } 00361 00366 operator bool() 00367 const 00368 { 00369 return (subject != 0); 00370 } 00371 00376 bool 00377 operator!() 00378 const 00379 { 00380 return (subject == 0); 00381 } 00382 00383 inline bool 00384 operator==(const aegis_shared_ptr &rhs) 00385 const 00386 { 00387 return (subject == rhs.get()); 00388 } 00389 00390 template<class U> 00391 inline bool 00392 operator==(const aegis_shared_ptr<U> &rhs) 00393 const 00394 { 00395 return (subject == rhs.get()); 00396 } 00397 00398 inline bool 00399 operator!=(aegis_shared_ptr &rhs) 00400 const 00401 { 00402 return (subject != rhs.get()); 00403 } 00404 00405 template<class U> 00406 inline bool 00407 operator!=(aegis_shared_ptr<U> &rhs) 00408 const 00409 { 00410 return (subject != rhs.get()); 00411 } 00412 00413 inline bool 00414 operator<(aegis_shared_ptr &rhs) 00415 const 00416 { 00417 return (subject < rhs.get()); 00418 } 00419 00420 template<class U> 00421 inline bool 00422 operator<(aegis_shared_ptr<U> &rhs) 00423 const 00424 { 00425 return (subject < rhs.get()); 00426 } 00427 }; 00428 00429 #endif // COMMON_AC_SHARED_PTR_AEGIS_H