00001 #ifndef S11N_NET_S11N_MEMORY_HPP_INCLUDED 00002 #define S11N_NET_S11N_MEMORY_HPP_INCLUDED 1 00003 00004 #include <s11n.net/s11n/exception.hpp> // s11n_exception and friends 00005 00006 namespace s11n { 00007 00008 /** 00009 Calls s11n_traits<SerializableType>::cleanup_functor()(s). 00010 00011 This function is declared as no-throw because of its 00012 logical role in the destruction process, and dtors are 00013 normally prohibited from throwing. Any exceptions caught by 00014 this function are silently ignored (a warning might go out 00015 to a debug channel, probably cerr, but don't rely on it). 00016 00017 SerializableType requirements: 00018 00019 - Must be a Serializable. Specifically, it must have an 00020 s11n_traits specialization installed. 00021 00022 - s11n_traits<SerializableType>::cleanup_functor must be 00023 known to work properly for SerializableType. This is core 00024 to the whole cleanup functionality, which is core to 00025 protecting against leaks in the face of errors. 00026 00027 Technically, if the type can be delete()d without leaking 00028 pointers, it's safe for use with this function, but this 00029 function SHOULD NOT be used as general cleanup tool. It is 00030 ONLY intended to be used with REGISTERED Serializables. 00031 00032 This function guarantees not to leak when "cleaning up" 00033 containers holding unmanaged pointers as long as the 00034 associated cleanup_functors do their part. The model is 00035 such that once a cleanup_functor is in place for a given 00036 type, this function will inherently walk it and invoke the 00037 cleanup rules, which includes freeing any pointers along 00038 the way. 00039 00040 Added in 1.1.3. 00041 */ 00042 template <typename SerializableType> 00043 void cleanup_serializable( SerializableType & s ) throw(); 00044 00045 /** 00046 This overload provides cleanup handling for pointer 00047 types. This simplifies many algorithms over using 00048 s11n_traits<SerializableType>::cleanup_functor directly, as 00049 the algorithms do not need to care if they're using 00050 pointer-qualified types or not in order to clean them up 00051 properly. 00052 00053 SerializableType requirements are as for the non-pointered 00054 variant of this function, plus: 00055 00056 - delete aSerializableTypeInstance; must be well-formed and 00057 must neither throw nor invoke undefined behaviour. (Did 00058 you realize that "neither" is an exception to English's 00059 "i-before-e" rule?) 00060 00061 This function does nothing if s is null, otherwise it calls 00062 cleanup_serializable(*s), deletes s, then assigns it to 0. 00063 00064 Postcondition: (0 == s) 00065 00066 Added in 1.1.3. 00067 */ 00068 template <typename SerializableType> 00069 void cleanup_serializable( SerializableType * & s ) throw(); 00070 00071 00072 /** 00073 Intended for use with for_each(), this type cleans up 00074 Serializables using cleanup_serializable(). 00075 00076 Usage: 00077 00078 std::for_each( container.begin(), container.end(), cleaner_upper() ); 00079 00080 where the container is parameterized to hold Serializables. 00081 00082 Provided that the contained type(s) conform to 00083 cleanup_ptr's requirements, this will recursively clean up 00084 sub-sub-...subcontainers. 00085 00086 Note that Serializable containers should have a cleanup 00087 functor installed as part of their registration, making 00088 this class unnecessary for most cases: simply calling 00089 cleanup_serializable() will recursively walk/clean such 00090 containers. The underlying cleanup algos might use this 00091 type, however (at least one of them does). 00092 00093 Added in 1.1.3. 00094 00095 This type is usable as a Finalizer for 00096 s11n::refcount::rcptr, by the way. 00097 */ 00098 struct cleaner_upper 00099 { 00100 /** 00101 Calls cleanup_serializable<T>(t) 00102 */ 00103 template <typename T> 00104 void operator()( T & t ) throw() 00105 { 00106 cleanup_serializable<T>( t ); 00107 } 00108 /** 00109 Calls cleanup_serializable<T>(t). 00110 */ 00111 template <typename T> 00112 void operator()( T * & t ) throw() 00113 { 00114 cleanup_serializable<T>( t ); 00115 } 00116 }; 00117 00118 00119 /** 00120 An auto_ptr-like type intended to simplify 00121 pointer/exception safety in some deserialization algorithms 00122 by providing a way to completely and safely destroy 00123 partially-deserialized objects. 00124 00125 SerializableT must either have an explicit s11n_traits 00126 specialization installed or work properly with the default 00127 functor provided by s11n_traits::cleanup_functor. In 00128 practice, this means that types which manage the memory of 00129 their contained pointers are safe to work with the default, 00130 whereas the cleanup of unmanaged child pointers (e.g., std 00131 containers) requires a proper specialization. 00132 00133 Note that this type does not have copy/assignment ctors, 00134 due to the conventional constness of their right-hand 00135 sides: use the swap() or take() members to take over a 00136 pointer. 00137 00138 Added in 1.1.3. 00139 00140 00141 To consider for 1.3.x: reimplement this type on top of 00142 rcptr so that we can get sane copy semantics. 00143 */ 00144 template <typename SerializableT> 00145 struct cleanup_ptr 00146 { 00147 public: 00148 typedef SerializableT cleaned_type; 00149 private: 00150 cleaned_type * m_ptr; 00151 cleanup_ptr & operator=( const cleanup_ptr & ); // Not Implemented 00152 cleanup_ptr( const cleanup_ptr & ); // Not Implemented 00153 void cleanup() throw() 00154 { 00155 if( this->m_ptr ) 00156 { 00157 cleanup_serializable<cleaned_type>( this->m_ptr ); 00158 } 00159 } 00160 public: 00161 /** 00162 Constructs an object pointing to nothing. 00163 */ 00164 cleanup_ptr() throw() : m_ptr(0) 00165 { 00166 } 00167 /** 00168 Transfers ownership of p to this object. 00169 */ 00170 cleanup_ptr( cleaned_type * p ) throw() : m_ptr(p) 00171 { 00172 } 00173 00174 /** 00175 Uses s11n::cleanup_serializable<cleaned_type>() 00176 to free up up this->get(). 00177 */ 00178 ~cleanup_ptr() throw() 00179 { 00180 this->cleanup(); 00181 } 00182 /** 00183 Dereferences this object's pointed-to object. If 00184 this object does not point to anything it throws a 00185 std::runtime_error with an informative what() 00186 message explaining the error. 00187 */ 00188 cleaned_type & operator*() 00189 { 00190 if( ! this->m_ptr ) 00191 { 00192 throw s11n_exception( S11N_SOURCEINFO, 00193 "Attempt to dereference a null pointer via s11n::cleanup_ptr<>::operator*()" ); 00194 } 00195 return *this->m_ptr; 00196 } 00197 00198 /** 00199 Returns the same as get(). 00200 */ 00201 cleaned_type * operator->() throw() 00202 { 00203 return this->m_ptr; 00204 } 00205 00206 /** 00207 Returns this object's pointed-to object without 00208 transfering ownership. 00209 */ 00210 cleaned_type * get() throw() 00211 { 00212 return this->m_ptr; 00213 } 00214 00215 /** 00216 Transfers ownership of p to this object. This 00217 member takes the place of copy/assign operators, 00218 since those conventionally take a const right-hand 00219 argument. 00220 00221 Destroys the object this object pointed to before 00222 taking over ownership. 0 is a legal value for p. 00223 00224 If (p == this->get()) then this function does 00225 nothing. 00226 00227 Postcondition: p == this->get() 00228 */ 00229 void take( cleaned_type * p ) throw() 00230 { 00231 if( p != this->m_ptr ) 00232 { 00233 this->cleanup(); 00234 this->m_ptr = p; 00235 } 00236 } 00237 00238 /** 00239 Transfers ownership of this->get() to the 00240 caller. 00241 00242 Postcondition: 0 == this->get() 00243 */ 00244 cleaned_type * release() throw() 00245 { 00246 cleaned_type * x = this->m_ptr; 00247 this->m_ptr = 0; 00248 return x; 00249 } 00250 00251 /** 00252 Cleans up any pointed-to object and points this 00253 object at 0. Does nothing if this object points 00254 to no object. 00255 00256 Postcondition: 0 == this->get() 00257 */ 00258 void clean() throw() 00259 { 00260 this->take( 0 ); 00261 } 00262 00263 /** 00264 Swaps ownership of pointers with rhs. 00265 */ 00266 void swap( cleanup_ptr & rhs ) throw() 00267 { 00268 cleaned_type * x = this->m_ptr; 00269 this->m_ptr = rhs.m_ptr; 00270 rhs.m_ptr = x; 00271 } 00272 00273 /** 00274 Returns the same as (!this->get()). 00275 */ 00276 bool empty() const throw() 00277 { 00278 return 0 == this->m_ptr; 00279 } 00280 }; 00281 00282 namespace Detail { 00283 /** 00284 We use a custom auto_ptr<> work-alike in place of 00285 std::auto_ptr so that s11n compiles cleanly under C++0x, 00286 where auto_ptr is apparently deprecated. 00287 00288 This type is a subset of std::auto_ptr, the main difference being 00289 that it's not copyable. 00290 00291 Note that this type is functionally very different from 00292 s11n::cleanup_ptr, which specifically handles the details 00293 of cleaning up Serializables, whereas this type simply uses 00294 delete to destroy its contents. 00295 */ 00296 template <typename T> 00297 struct auto_ptr { 00298 auto_ptr( T * t ) : m_x(t) {} 00299 ~auto_ptr() { delete m_x; } 00300 T * get() const { return m_x; } 00301 T * release() { T * x = m_x; m_x = 0; return x; } 00302 T * operator->() const { return m_x; } 00303 void reset( T * x ) 00304 { 00305 if( x != m_x ) delete m_x; 00306 m_x = x; 00307 } 00308 /** Throws if !this->get(). */ 00309 T & operator*() const 00310 { 00311 if( ! m_x ) throw s11n_exception( S11N_SOURCEINFO, 00312 "Attempt to dereference a null pointer via s11n::Detail::auto_ptr<>::operator*()" ); 00313 return *m_x; 00314 } 00315 private: 00316 T * m_x; 00317 auto_ptr( auto_ptr const & ); 00318 auto_ptr & operator=(auto_ptr const &); 00319 }; 00320 00321 } // namespace Detail 00322 } // namespace s11n 00323 #include <s11n.net/s11n/memory.tpp> 00324 #endif // S11N_NET_S11N_MEMORY_HPP_INCLUDED