![]() |
Object-oriented Scientific Computing Library: Version 0.910
|
00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2011-2012, Andrew W. Steiner 00005 00006 This file is part of O2scl. It was adapted from the shared_ptr 00007 implementation of aegis, available at aegis.sourceforge.net. 00008 00009 O2scl is free software; you can redistribute it and/or modify 00010 it under the terms of the GNU General Public License as published by 00011 the Free Software Foundation; either version 3 of the License, or 00012 (at your option) any later version. 00013 00014 O2scl 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 00017 GNU General Public License for more details. 00018 00019 You should have received a copy of the GNU General Public License 00020 along with O2scl. If not, see <http://www.gnu.org/licenses/>. 00021 00022 ------------------------------------------------------------------- 00023 */ 00024 // 00025 // aegis - project change supervisor 00026 // Copyright (C) 2007, 2008 Peter Miller 00027 // 00028 // This program is free software; you can redistribute it and/or 00029 // modify it under the terms of the GNU General Public License 00030 // as published by the Free Software Foundation; either version 3 00031 // of the License, or (at your option) any later version. 00032 // 00033 // This program is distributed in the hope that it will be useful, 00034 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00035 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00036 // GNU General Public License for more details. 00037 // 00038 // You should have received a copy of the GNU General Public 00039 // License along with this program. If not, see 00040 // <http://www.gnu.org/licenses/>. 00041 00042 #ifndef O2SCL_SHARED_PTR_H 00043 #define O2SCL_SHARED_PTR_H 00044 00045 #include <cassert> 00046 00047 #ifndef DOXYGENP 00048 namespace o2scl { 00049 #endif 00050 00051 /** \brief The internal shared pointer class used if no TR1 or Boost 00052 implementation is available 00053 00054 See also \ref o2_shared_ptr . 00055 00056 This class was based on the Aegis <tt>shared_ptr</tt> class from 00057 http:://aegis.sourceforge.net, but is implemented in \o2 using a 00058 template struct rather than a define constant. 00059 */ 00060 template<class T> class o2_int_shared_ptr { 00061 00062 private: 00063 00064 /** \brief Reference count 00065 00066 Documentation from Aegis: 00067 \verbatim 00068 The reference_count instance variable is used to remember the 00069 location of the reference count. By having the reference count 00070 separate from the subject, we can cope with compatible pointers, 00071 not just exact pointers. 00072 00073 This is not ideal because it allocates huge numbers of small 00074 objects. Some heap implementations go slowly when faced with 00075 many small allocations. Some heap implementations waste a lot of 00076 memory when faced with many small allocations. 00077 \endverbatim 00078 */ 00079 long *reference_count; 00080 00081 /** \brief Object being pointed to 00082 00083 Documentation from Aegis: 00084 \verbatim 00085 The subject instance variable is used to remember the location 00086 of the object being reference counted. By having it separate 00087 from the reference count, we can skip one indirection. 00088 \endverbatim 00089 */ 00090 T *subject; 00091 00092 public: 00093 00094 /** \brief Create an empty shared_ptr 00095 */ 00096 o2_int_shared_ptr() : reference_count(0),subject(0) { 00097 assert(valid()); 00098 } 00099 00100 /** \brief Create a shared pointer 00101 00102 This constructor permits initialization from any compatable 00103 pointer where \c Y must be a complete type. 00104 */ 00105 template<class Y> explicit o2_int_shared_ptr(Y *rhs) : 00106 reference_count(0), subject(0) { 00107 assert(valid()); 00108 if (rhs) { 00109 reference_count = new long(1); 00110 subject = rhs; 00111 } 00112 assert(valid()); 00113 } 00114 00115 ~o2_int_shared_ptr() { 00116 assert(valid()); 00117 if (reference_count) { 00118 --*reference_count; 00119 if (*reference_count <= 0) { 00120 delete subject; 00121 subject = 0; 00122 delete reference_count; 00123 reference_count = 0; 00124 } 00125 } 00126 } 00127 00128 /** \brief Copy constructor. 00129 */ 00130 o2_int_shared_ptr(const o2_int_shared_ptr &rhs) : 00131 reference_count(0), subject(0) { 00132 assert(rhs.valid()); 00133 if (rhs.subject) { 00134 assert(rhs.reference_count); 00135 reference_count = rhs.reference_count; 00136 subject = rhs.subject; 00137 ++*reference_count; 00138 } 00139 assert(valid()); 00140 } 00141 00142 template <class Y> friend class o2_int_shared_ptr; 00143 00144 /** \brief Copy constructor for compatible pointer types 00145 */ 00146 template<class Y> o2_int_shared_ptr(const o2_int_shared_ptr<Y> &rhs) : 00147 reference_count(0), subject(0) { 00148 assert(rhs.valid()); 00149 if (rhs.subject) { 00150 assert(rhs.reference_count); 00151 reference_count = rhs.reference_count; 00152 subject = rhs.subject; 00153 ++*reference_count; 00154 } 00155 assert(valid()); 00156 } 00157 00158 /** \brief Test if the shared_ptr object is valid 00159 00160 This method verifies that the internal state of 00161 the shared pointer object is valid. 00162 */ 00163 bool valid() const { 00164 return ((reference_count != 0) ? (*reference_count > 0 && 00165 subject != 0) : (subject == 0)); 00166 } 00167 00168 /** \brief Swap 00169 00170 Swap the contents of two o2_int_shared_ptr<T> objects. 00171 This method is more efficient than manually swapping 00172 shared_ptr objects using a copy constructor or temporary. 00173 */ 00174 void swap(o2_int_shared_ptr &rhs) { 00175 assert(valid()); 00176 assert(rhs.valid()); 00177 long *temp_reference_count = reference_count; 00178 T *temp_subject = subject; 00179 reference_count = rhs.reference_count; 00180 subject = rhs.subject; 00181 rhs.reference_count = temp_reference_count; 00182 rhs.subject = temp_subject; 00183 } 00184 00185 /** \brief Drop the reference and set the pointer to zero 00186 */ 00187 void reset() { 00188 // swap with a NULL pointer 00189 o2_int_shared_ptr tmp; 00190 this->swap(tmp); 00191 } 00192 00193 /** \brief Assignment operator 00194 */ 00195 o2_int_shared_ptr &operator=(const o2_int_shared_ptr &rhs) { 00196 assert(valid()); 00197 assert(rhs.valid()); 00198 if (this != &rhs) { 00199 // Documentation from Aegis: 00200 // 00201 // In case you haven't seen the swap() technique to 00202 // implement copy assignment before, here's what it does: 00203 // 00204 // 1) Create a temporary o2_int_shared_ptr<> instance via the 00205 // copy constructor, thereby increasing the reference 00206 // count of the source object. 00207 // 00208 // 2) Swap the internal object pointers of *this and the 00209 // temporary o2_int_shared_ptr<>. After this step, *this 00210 // already contains the new pointer, and the old pointer 00211 // is now managed by temp. 00212 // 00213 // 3) The destructor of temp is executed, thereby 00214 // unreferencing the old object pointer. 00215 // 00216 // This technique is described in Herb Sutter's "Exceptional 00217 // C++", and has a number of advantages over conventional 00218 // approaches: 00219 // 00220 // - Code reuse by calling the copy constructor. 00221 // - Strong exception safety for free. 00222 // - Self assignment is handled implicitly. 00223 // - Simplicity. 00224 // - It just works and is hard to get wrong; i.e. you can 00225 // use it without even thinking about it to implement 00226 // copy assignment where ever the object data is managed 00227 // indirectly via a pointer, which is very common. 00228 // 00229 o2_int_shared_ptr temp(rhs); 00230 this->swap(temp); 00231 assert(valid()); 00232 assert(rhs.valid()); 00233 } 00234 return *this; 00235 } 00236 00237 /** \brief Assignment operator for compatible pointer types 00238 */ 00239 template<class Y> o2_int_shared_ptr &operator= 00240 (const o2_int_shared_ptr<Y> &rhs) { 00241 assert(valid()); 00242 assert(rhs.valid()); 00243 if (this != (o2_int_shared_ptr *)&rhs) { 00244 o2_int_shared_ptr tmp(rhs); 00245 this->swap(tmp); 00246 assert(valid()); 00247 assert(rhs.valid()); 00248 } 00249 return *this; 00250 } 00251 00252 /** \brief Dereference operator 00253 */ 00254 T &operator*() const { 00255 assert(subject != 0); 00256 return *subject; 00257 } 00258 00259 /** \brief Pointing at operator 00260 */ 00261 T *operator->() const { 00262 assert(subject != 0); 00263 return subject; 00264 } 00265 00266 /** \brief Return a pointer to the object 00267 */ 00268 T *get() const { 00269 return subject; 00270 } 00271 00272 /** \brief Return true if the pointer is not zero. 00273 */ 00274 operator bool() const { 00275 return (subject != 0); 00276 } 00277 00278 /** \brief Logical not operator 00279 00280 Return true if and only if the pointer is zero. 00281 */ 00282 bool operator!() const { 00283 return (subject == 0); 00284 } 00285 00286 /** \brief Test equality 00287 */ 00288 inline bool operator==(const o2_int_shared_ptr &rhs) const { 00289 return (subject == rhs.get()); 00290 } 00291 00292 /** \brief Test equality for compatible pointer types 00293 */ 00294 template<class U> inline bool operator== 00295 (const o2_int_shared_ptr<U> &rhs) const { 00296 return (subject == rhs.get()); 00297 } 00298 00299 /** \brief Test inequality 00300 */ 00301 inline bool operator!=(o2_int_shared_ptr &rhs) const { 00302 return (subject != rhs.get()); 00303 } 00304 00305 /** \brief Test inequality for compatible pointer types 00306 */ 00307 template<class U> inline bool operator!=(o2_int_shared_ptr<U> &rhs) const { 00308 return (subject != rhs.get()); 00309 } 00310 00311 /** \brief Less than operator 00312 */ 00313 inline bool operator<(o2_int_shared_ptr &rhs) const { 00314 return (subject < rhs.get()); 00315 } 00316 00317 /** \brief Less than operator for compatible pointer types 00318 */ 00319 template<class U> inline bool operator<(o2_int_shared_ptr<U> &rhs) const { 00320 return (subject < rhs.get()); 00321 } 00322 00323 }; 00324 00325 #ifndef DOXYGENP 00326 } 00327 #endif 00328 00329 #ifdef DOXYGENP 00330 00331 /** \brief A struct to provide the shared_ptr type 00332 00333 This object exists in order to provide the shared_ptr template 00334 type used in \o2. The full specification of a shared pointer 00335 in \o2 for an object of type \c T is thus 00336 \verbatim 00337 o2scl::o2_shared_ptr<T>::type 00338 \endverbatim 00339 In a default \o2 installation, \ref type (as given below) 00340 is a typedef of 00341 \verbatim 00342 std::tr1::shared_ptr<T> 00343 \endverbatim 00344 If <tt>O2SCL_NO_TR1_MEMORY</tt> is defined, then \ref type is 00345 a typedef of \ref o2_int_shared_ptr, unless <tt>O2SCL_HAVE_BOOST</tt> 00346 is defined, in which case \ref type is a typedef of 00347 \verbatim 00348 boost::shared_ptr<T> 00349 \endverbatim 00350 00351 See also the discussion at http://www.gotw.ca/gotw/079.htm . This 00352 struct won't be necessary when C++ allows template typedef's as 00353 part of the C++11 standard http://en.wikipedia.org/wiki/C%2B%2B11 00354 , but very few compilers have implemented this standard yet. 00355 */ 00356 template<class T> struct o2_shared_ptr { 00357 /// The actual shared_ptr type 00358 typedef std::tr1::shared_ptr<T> type; 00359 }; 00360 00361 #else 00362 00363 // ------------------------------------------------------------------- 00364 // Define the o2_shared_ptr struct according to the installation settings 00365 00366 // AWS - 11/29/11: I can't remember if the #include statements have 00367 // to be outside the o2scl namespace, but I make sure they're 00368 // outside just in case it matters. 00369 00370 #ifndef O2SCL_NO_TR1_MEMORY 00371 00372 #include <tr1/memory> 00373 namespace o2scl { 00374 template<class T> struct o2_shared_ptr { 00375 typedef std::tr1::shared_ptr<T> type; 00376 }; 00377 } 00378 00379 #else 00380 00381 #if O2SCL_HAVE_BOOST 00382 00383 #include <boost/shared_ptr.hpp> 00384 namespace o2scl { 00385 template<class T> struct o2_shared_ptr { 00386 typedef boost::shared_ptr<T> type; 00387 }; 00388 } 00389 00390 #else 00391 00392 namespace o2scl { 00393 template<class T> struct o2_shared_ptr { 00394 typedef o2_int_shared_ptr<T> type; 00395 }; 00396 } 00397 00398 // end of if O2SCL_HAVE_BOOST 00399 #endif 00400 00401 // end of if O2SCL_NO_TR1_MEMORY 00402 #endif 00403 00404 // end of ifdef DOXYGENP 00405 #endif 00406 00407 // ------------------------------------------------------------------- 00408 00409 // end of ifdef O2SCL_SHARED_PTR_H 00410 #endif
Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).