00001 #ifndef s11n_net_refcount_REFCOUNT_HPP_INCLUDED 00002 #define s11n_net_refcount_REFCOUNT_HPP_INCLUDED 1 00003 // reminders to self: 00004 // - think about lazyassptr<T> which lazily instantiates its 00005 // pointee. That would take a Constructor functor, providing symmetry 00006 // with rcptr<>. 00007 00008 #include <map> 00009 00010 00011 /** 00012 The refcount namespace encapsulates code for a reference-counted 00013 smart pointer. It is capable of tracking and destroying objects and 00014 arbitrary pointers (including void pointers) and destroying them 00015 using a user-defined finalizer functor. This allows, e.g., the 00016 reference-counted sharing of memory allocated via malloc() or by 00017 third-party functions such as dlopen() or sqlite3_open(). 00018 00019 This code is not generic, industrial-strength reference counting 00020 and is as much an experiment as anything else. 00021 00022 Author: stephan at s11n dot net 00023 00024 License: Public Domain 00025 */ 00026 namespace refcount { 00027 00028 00029 /** 00030 A no-op "destructor" for use with rcptr. 00031 */ 00032 struct no_delete_finalizer 00033 { 00034 /** Assigs t to 0 without deleting t. */ 00035 template <typename T> 00036 void operator()( T * & t ) 00037 { 00038 t = 0; 00039 } 00040 }; 00041 00042 /** 00043 The default destructor/cleanup functor for use with 00044 rcptr<>. 00045 */ 00046 struct plain_delete_finalizer 00047 { 00048 /** 00049 Calls delete t and assigns t to 0. 00050 00051 Specialized dtors need not call delete, but should 00052 assign t to 0, as this simplifies some client code. 00053 00054 T must be non-CVP-qualified and for this 00055 implementation (delete t) must be legal. 00056 */ 00057 template <typename T> 00058 void operator()( T * & t ) 00059 { 00060 delete t; 00061 t = 0; 00062 } 00063 }; 00064 00065 /** 00066 All classes in this namespace are "internal details" of the 00067 classes in the refcount namespace, and should not be 00068 directly used by client code. 00069 */ 00070 namespace Detail 00071 { 00072 /** 00073 Internal detail for dereferencing pointers. 00074 */ 00075 template <typename T> 00076 struct ref_type 00077 { 00078 /** Same as (T&). */ 00079 typedef T & type; 00080 /** Returns *t. */ 00081 static type deref( T *t ) { return *t; } 00082 }; 00083 /** 00084 Internal detail for dereferencing pointers. 00085 */ 00086 template <> 00087 struct ref_type<void> 00088 { 00089 /** Same as (void*&). */ 00090 typedef void * & type; 00091 /** Returns xx. */ 00092 static type deref( type xx ) { return xx; } 00093 }; 00094 } // namespace Detail 00095 00096 /** 00097 A bare-bones non-intrusive reference-counted pointer type 00098 with the ability for the client to specify a 00099 finalization/destruction functor for the pointed-to type. 00100 00101 HandleT must be a non-CVP-qualified type. As a special 00102 case, if HandleT is void then some code in this class will 00103 work a bit differently, notably the operator*(), because we 00104 cannot form a reference to void. Void is supported because 00105 (void *) is commonly used for opaque handles (e.g. libdl) 00106 or multibyte string pointers (e.g. libsqlite3). 00107 00108 FinalizerT must be a type compatible with the 00109 plain_delete_finalizer interface. A default-constructed 00110 instance of that FinalizerT type will be created to 00111 "finalize" an object when the reference count for that 00112 object drops to zero. The exact behaviour of the FinalizerT 00113 is not specified here, but semantically it must "finalize" 00114 the object passed to it. The default finalizer simply 00115 deletes the object, whereas a more advanced finalizer might 00116 push the object into a garbage collection pool. For 00117 purposes of this class, after finalization of an object, 00118 client code (and this type) should no longer use the object 00119 - it is considered to be destroyed. 00120 00121 This type does not currently have any built-in support for 00122 copy-on-write, so all copies are extremely shallow. 00123 00124 Notes of Utmost Significance to Potential Users: 00125 00126 - Implicit conversions to/from HandleT are not implemented 00127 after much deliberation on the subject. Clients will *have* 00128 to know they're using this class, as opposed to a plain 00129 pointer type. This is safest for everyone, IMO. 00130 00131 - Don't mix plain and rcptr-hosted pointers, as the rcptr 00132 wrappers own the pointers and will clean them up, leaving 00133 any unadorned pointers dangling. 00134 00135 - Thread safety: no special guarantees, along with lots of 00136 caveats and potential gotchas. 00137 00138 - Don't mix different smart pointer types, not even 00139 rcptrs with the same HandleT type but different 00140 FinalizerT types. This will almost certainly bring about 00141 the incorrect finalization of a pointer. 00142 00143 - The usage of a finalizer functor means that this type can 00144 be used with arbitrary types, regardless of whether the 00145 delete operation is legal or not on them. For example, the 00146 client code for which this class was written uses a functor 00147 to finalize sqlite3 database handles using the 00148 sqlite3_close() function. 00149 00150 00151 00152 Design notes: 00153 00154 - While originally based off of the presentation of 00155 rc-pointers in Meyers' "More Effective C++", Item 29, i 00156 believe his approach to storing the reference count in his 00157 RCIPtr class is flawed, as it allows multiple rc-pointers 00158 to delete the same pointer. Consider: 00159 00160 \code 00161 typedef RCIPtr<MyType> myPtrType; 00162 MyType * t = new MyType; 00163 myPtrType x(t); 00164 myPtrType y(t); 00165 \endcode 00166 00167 In theory, his presentation (admittedly 10+ years old now) 00168 would cause a double-delete for that case. In this model, 00169 that case is handled as if we had constructed y using y(x) 00170 instead of y(t), so both x and y share the reference count. 00171 00172 - The reference count is stored in a static-space std::map, 00173 and that map is specific to this type and its combination 00174 of HandleT/FinalizerT types. If we made the map only 00175 specific to the HandleT, then we would get 00176 strange/undesired behaviour when we did: 00177 00178 \code 00179 rcptr<T1,finalizerT1> p1( new T1 ); 00180 rcptr<T2,finalizerT2> p2( p1.get() ); 00181 \endcode 00182 00183 because the actual finalizer used would be the one for 00184 which the rcptr is destroyed *last*. Since destruction 00185 order is not always determinate, this mixture would be a 00186 bad idea. Note that it is still illegal to add the same 00187 pointer to multiple different shared pointer types. The 00188 above example, while illegal, will at least cause 00189 determinate behaviour: a double finalization (but the order 00190 is still unspecified in the general case)! 00191 00192 00193 Fundamental differences between rcptr and 00194 boost::shared_ptr: 00195 00196 - rcptr::take() allows client to take ownership of a 00197 pointer away from rcptr. According to the shared_ptr FAQ, 00198 this isn't technically feasible in that class due to their 00199 handling of the user-defined finalizer. 00200 00201 - rcptr has no explicit support for multi-threading. 00202 00203 - shared_ptr does not handle the following code "correctly" 00204 (IMO): 00205 00206 typedef boost::shared_ptr<AStruct> SP; 00207 SP sp1( new AStruct ); 00208 SP sp2( sp1.get() ); 00209 // sp1.use_count() is 1, not 2 00210 // This causes a double deletion 00211 00212 rcptr handles that case transparently. 00213 00214 */ 00215 template <typename HandleT, 00216 typename FinalizerT = plain_delete_finalizer> 00217 class rcptr 00218 { 00219 public: 00220 /** 00221 The basic type of object pointed to. 00222 */ 00223 typedef HandleT type; 00224 /** 00225 The basic pointer type. 00226 */ 00227 typedef type * pointer_type; 00228 /** The type of functor used to clean up pointer_type objects. */ 00229 typedef FinalizerT finalizer_type; 00230 private: 00231 mutable pointer_type m_ptr; 00232 typedef int counter_type; 00233 typedef std::map<pointer_type,counter_type> map_type; 00234 /** Returns a shared map holding the reference 00235 counts for all instances of pointer_type 00236 tracked by this class. This is not 00237 post-main() safe. 00238 */ 00239 static map_type & map() 00240 { 00241 static map_type bob; 00242 return bob; 00243 } 00244 00245 /** 00246 Decrements the reference count to ptr. If the 00247 count goes to 0, an instance of finalizer_type is 00248 used to "destruct" ptr. On success, the current 00249 reference count is returned. If 0 is returned, 00250 ptr should be considered invalid (though this 00251 actually depends on finalizer_type's 00252 implementation, the semantics are that destruction 00253 leaves us with an unusable object). On error 00254 (passed a null ptr), a number less than 0 is 00255 returned. 00256 */ 00257 static counter_type decrement( pointer_type & ptr ) 00258 { 00259 if( ! ptr ) return false; 00260 typename map_type::iterator it = map().find(ptr); 00261 if( map().end() == it ) return false; 00262 if( 0 == (*it).second ) return 0; // can happen, e.g., if take() is called. 00263 counter_type rc = --(*it).second; 00264 if ( 0 == rc ) 00265 { 00266 map().erase( it ); 00267 finalizer_type()( ptr ); 00268 } 00269 return rc; 00270 } 00271 00272 /** 00273 If ! ptr, does nothing, else it increases the 00274 reference count for ptr by one. Returns the current 00275 reference count (guaranteed to be 1 or higher) on 00276 success, or a negative number if passed a null ptr. 00277 */ 00278 static counter_type increment( pointer_type & ptr ) 00279 { 00280 if( ! ptr ) return -1; 00281 return ++(map()[ptr]); 00282 } 00283 00284 // bool safety_first() 00285 // { 00286 // if( ! this->m_ptr ) return false; 00287 // if( 0 == this->ref_count() ) 00288 // { // dangling pointer, it seems 00289 // this->m_ptr = 0; 00290 // } 00291 // return 0 != this->m_ptr; 00292 // } 00293 public: 00294 /** 00295 Transfers ownership of h, or allows h to 00296 participate in ownership with other rcptr 00297 objects pointing at h. 00298 */ 00299 explicit rcptr( pointer_type h ) : m_ptr(h) 00300 { 00301 this->increment( this->m_ptr ); 00302 } 00303 /** 00304 rhs and this object will both manage the same 00305 underlying pointer. 00306 */ 00307 rcptr( rcptr const & rhs ) : m_ptr(rhs.m_ptr) 00308 { 00309 this->increment( this->m_ptr ); 00310 } 00311 /** 00312 First disowns any connected pointer (using 00313 take(0)), then rhs and this object will 00314 both manage the same underlying pointer. If 00315 by chance rhs.get() == this->get() when 00316 this function starts then this function 00317 does nothing and has no side effects. 00318 */ 00319 rcptr & operator=( rcptr const & rhs ) 00320 { 00321 if( rhs.m_ptr == this->m_ptr ) return *this; 00322 this->decrement( this->m_ptr ); 00323 this->m_ptr = rhs.m_ptr; 00324 this->increment( this->m_ptr ); 00325 return *this; 00326 } 00327 /** 00328 An empty shared pointer, useful only as a target of 00329 assigment or take(). 00330 */ 00331 rcptr() : m_ptr(0) 00332 {} 00333 00334 /** 00335 Efficiently swaps this object and rhs, such that they 00336 swap ownership of their underlying pointers. 00337 This does not require fiddling with the reference 00338 counts, so it is much faster than using an rcptr 00339 copy to perform a swap. 00340 */ 00341 void swap( rcptr & rhs ) 00342 { 00343 if( this->m_ptr != rhs ) 00344 { 00345 pointer_type x = this->m_ptr; 00346 this->m_ptr = rhs.m_ptr; 00347 rhs.m_ptr = x; 00348 } 00349 } 00350 00351 00352 /** 00353 See decrement(); 00354 */ 00355 ~rcptr() 00356 { 00357 this->decrement( this->m_ptr ); 00358 } 00359 00360 /** Returns (this->m_ptr == rhs.m_ptr). */ 00361 bool operator==( rcptr const & rhs ) const 00362 { 00363 return this->m_ptr == rhs.m_ptr; 00364 } 00365 /** Returns (this->m_ptr != rhs.m_ptr). */ 00366 bool operator!=( rcptr const & rhs ) const 00367 { 00368 return this->m_ptr != rhs.m_ptr; 00369 } 00370 00371 /** 00372 Returns this->get() < rhs.get(). Implemented so that 00373 this type can be used as keys in STL containers. 00374 */ 00375 bool operator<( rcptr const & rhs ) const 00376 { 00377 return this->m_ptr < rhs.m_ptr; 00378 } 00379 00380 /** Returns this object's underlying pointer, which 00381 may be 0. This does not transfer ownership. This 00382 object still owns (or participates in the 00383 ownership of) the returned pointer. 00384 */ 00385 pointer_type get() const { return this->m_ptr; } 00386 00387 /** 00388 Gives ownership of p to this object (or a 00389 collection of like-types rcptr objects). Drops 00390 ownership of this->get() before making the 00391 takeover. If (this->get() == p) then this function 00392 does nothing. 00393 */ 00394 void take( pointer_type p ) 00395 { 00396 if( p == this->m_ptr ) return; 00397 this->decrement( this->m_ptr ); 00398 this->increment( this->m_ptr = p ); 00399 } 00400 00401 /** 00402 Transfers ownership of this->get() to the caller. 00403 00404 ALL rcptr<> objects which point to that object 00405 (except this rcptr) STILL point to that object, 00406 but they will not activate the destructor functor 00407 when they die, so they are safe as long as they 00408 remain unsued or are destroyed before the "raw" 00409 pointer returned from this function is destroyed. 00410 */ 00411 pointer_type take() 00412 { 00413 if( this->m_ptr ) 00414 { 00415 pointer_type t = this->m_ptr; 00416 this->map().erase( this->m_ptr ); 00417 this->m_ptr = 0; 00418 return t; 00419 } 00420 return this->m_ptr; 00421 } 00422 00423 /** 00424 The same as this->get(). 00425 */ 00426 pointer_type operator->() const { return this->m_ptr; } 00427 00428 00429 /** 00430 reference_type is the same as (T&) unless T is void, 00431 in which case it is the same as (void*&) because 00432 (void&) is not legal. 00433 */ 00434 typedef typename Detail::ref_type<type>::type reference_type; 00435 00436 /** 00437 The same as *(this->get()). Behaviour is undefined 00438 if (!this->get()). We would throw an exception, but 00439 this code is specifically intended for use on 00440 platforms where exceptions are not allowed or not 00441 supported (e.g. some embedded platforms). 00442 00443 SPECIAL CASE: rcptr::type is void 00444 00445 If rcptr::type is void then this function returns a 00446 refernce to a pointer instead of a reference. This 00447 is to allow this type to work with (void*) handle 00448 types, such as handles returned from dlopen() or 00449 memory returned from malloc(). Finalizers for such 00450 handles could call dlclose() or free(), as 00451 appropriate. 00452 */ 00453 reference_type operator*() const 00454 { 00455 return Detail::ref_type<type>::deref( this->m_ptr ); 00456 } 00457 /** 00458 Returns the number of references to this object's pointer, 00459 or zero if no pointer is bound. This function should be 00460 considered a debugging/informational function, and not 00461 a "feature" of this type. 00462 00463 Complexity = that of a std::map lookup. 00464 */ 00465 size_t ref_count() const 00466 { 00467 if( ! this->m_ptr ) return 0; 00468 typename map_type::iterator it = map().find(this->m_ptr); 00469 return ( map().end() == it ) ? 0 : (*it).second; 00470 } 00471 00472 /** 00473 Returns the same as (!this->get()). 00474 */ 00475 bool empty() const { return 0 == this->m_ptr; } 00476 00477 // Adding deep copy support requires a copy ctor/functor for our 00478 // pointee type, but this type should/must be usable with opaque 00479 // pointer handles as well as object pointers (e.g. sqlite3 db handles 00480 // and ncurses WINDOW handles). But if you did want to implement 00481 // copy(), here's how you might go about doing it... 00482 // /** 00483 // Makes a copy of p using (new type(*p)) and 00484 // transfers ownership of that copy to this 00485 // object. Further copies of this object will point to 00486 // that copy unless/until copy() is called on 00487 // them. This function is intended to simplify 00488 // implementation of copy-on-write. If p is null then 00489 // this object points to null. 00490 00491 // To force an rcptr to copy its current pointer, simply 00492 // call ptr.copy( ptr.get() ). 00493 // */ 00494 // void copy( pointer_type p ) 00495 // { 00496 // pointer_type x = this->m_ptr; 00497 // if( p ) 00498 // { 00499 // this->m_ptr = new type(*p); 00500 // this->increment( this->m_ptr ); 00501 // } 00502 // else 00503 // { 00504 // this->m_ptr = 0; 00505 // } 00506 // this->decrement(x); 00507 // } 00508 // Some things to consider: 00509 // bool m_shareable; 00510 // bool shareable() const { return this->m_shareable; } 00511 // void shareable( bool s ) { this->m_shareable = s; } 00512 // bool shared() const { return this->ref_count() > 1; } 00513 00514 00515 }; 00516 00517 00518 } // namespaces 00519 00520 00521 #endif // s11n_net_refcount_REFCOUNT_HPP_INCLUDED