Actual source code: ALE_mem.hh
1: #ifndef included_ALE_mem_hh
2: #define included_ALE_mem_hh
3: // This should be included indirectly -- only by including ALE.hh
6: #include <memory>
7: #include <typeinfo>
8: #include <petsc.h>
9: #include <ALE_log.hh>
11: #ifdef ALE_HAVE_CXX_ABI
12: #include <cxxabi.h>
13: #endif
15: namespace ALE {
16: template <class T>
17: static const char *getClassName() {
18: const std::type_info& id = typeid(T);
19: const char *id_name;
21: #ifdef ALE_HAVE_CXX_ABI
22: // If the C++ ABI API is available, we can use it to demangle the class name provided by type_info.
23: // Here we assume the industry standard C++ ABI as described in http://www.codesourcery.com/cxx-abi/abi.html.
24: int status;
25: char *id_name_demangled = abi::__cxa_demangle(id.name(), NULL, NULL, &status);
27: if (status != 0) {
28: id_name = id.name();
29: } else {
30: id_name = id_name_demangled;
31: }
32: #else
33: id_name = id.name();
34: #endif
35: return id_name;
36: };
37: template <class T>
38: static void restoreClassName(const char *id_name) {
39: #ifdef ALE_HAVE_CXX_ABI
40: // Free the name malloc'ed by __cxa_demangle
41: free((char *) id_name);
42: #endif
43: };
45: // This UNIVERSAL allocator class is static and provides allocation/deallocation services to all allocators defined below.
46: class universal_allocator {
47: public:
48: typedef std::size_t size_type;
49: static char* allocate(const size_type& sz);
50: static void deallocate(char *p, const size_type& sz);
51: static size_type max_size();
52: };
54: // This allocator implements create and del methods, that act roughly as new and delete in that they invoke a constructor/destructor
55: // in addition to memory allocation/deallocation.
56: // An additional (and potentially dangerous) feature allows an object of any type to be deleted so long as its size has been provided.
57: template <class T>
58: class polymorphic_allocator {
59: public:
60: typedef typename std::allocator<T> Alloc;
61: // A specific allocator -- alloc -- of type Alloc is used to define the correct types and implement methods
62: // that do not allocate/deallocate memory themselves -- the universal _alloc is used for that (and only that).
63: // The relative size sz is used to calculate the amount of memory to request from _alloc to satisfy a request to alloc.
64: typedef typename Alloc::size_type size_type;
65: typedef typename Alloc::difference_type difference_type;
66: typedef typename Alloc::pointer pointer;
67: typedef typename Alloc::const_pointer const_pointer;
68: typedef typename Alloc::reference reference;
69: typedef typename Alloc::const_reference const_reference;
70: typedef typename Alloc::value_type value_type;
72: static Alloc alloc; // The underlying specific allocator
73: static typename Alloc::size_type sz; // The size of T universal units of char
75: polymorphic_allocator() {};
76: polymorphic_allocator(const polymorphic_allocator& a) {};
77: template <class TT>
78: polymorphic_allocator(const polymorphic_allocator<TT>& aa){};
79: ~polymorphic_allocator() {};
81: // Reproducing the standard allocator interface
82: pointer address(reference _x) const { return alloc.address(_x); };
83: const_pointer address(const_reference _x) const { return alloc.address(_x); };
84: T* allocate(size_type _n) { return (T*)universal_allocator::allocate(_n*sz); };
85: void deallocate(pointer _p, size_type _n) { universal_allocator::deallocate((char*)_p, _n*sz); };
86: void construct(pointer _p, const T& _val) { alloc.construct(_p, _val); };
87: void destroy(pointer _p) { alloc.destroy(_p); };
88: size_type max_size() const { return (size_type)floor(universal_allocator::max_size()/sz); };
89: // conversion typedef
90: template <class TT>
91: struct rebind { typedef polymorphic_allocator<TT> other;};
92:
93: T* create(const T& _val = T());
94: void del(T* _p);
95: template<class TT> void del(TT* _p, size_type _sz);
96: };
98: template <class T>
99: typename polymorphic_allocator<T>::Alloc polymorphic_allocator<T>::alloc;
101: //IMPORTANT: allocator 'sz' calculation takes place here
102: template <class T>
103: typename polymorphic_allocator<T>::size_type polymorphic_allocator<T>::sz =
104: (typename polymorphic_allocator<T>::size_type)(ceil(sizeof(T)/sizeof(char)));
106: template <class T>
107: T* polymorphic_allocator<T>::create(const T& _val) {
108: // First, allocate space for a single object
109: T* _p = (T*)universal_allocator::allocate(sz);
110: // Construct an object in the provided space using the provided initial value
111: this->alloc.construct(_p, _val);
112: return _p;
113: }
115: template <class T>
116: void polymorphic_allocator<T>::del(T* _p) {
117: _p->~T();
118: universal_allocator::deallocate((char*)_p, polymorphic_allocator<T>::sz);
119: }
121: template <class T> template <class TT>
122: void polymorphic_allocator<T>::del(TT* _p, size_type _sz) {
123: _p->~TT();
124: universal_allocator::deallocate((char*)_p, _sz);
125: }
128: // An allocator all of whose events (allocation, deallocation, new, delete) are logged using ALE_log facilities.
129: // O is true if this is an Obj allocator (that's the intended use, anyhow).
130: template <class T, bool O = false>
131: class logged_allocator : public polymorphic_allocator<T> {
132: private:
133: static bool _log_initialized;
134: static LogCookie _cookie;
135: static int _allocate_event;
136: static int _deallocate_event;
137: static int _construct_event;
138: static int _destroy_event;
139: static int _create_event;
140: static int _del_event;
141: //
142: static void __log_initialize();
143: static LogEvent __log_event_register(const char *class_name, const char *event_name);
144: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
145: // FIX: should PETSc memory logging machinery be wrapped by ALE_log like the rest of the logging stuff?
146: PetscObject _petscObj; // this object is used to log memory in PETSc
147: #endif
148: void __alloc_initialize();
149: void __alloc_finalize();
150: public:
151: // Present the correct allocator interface
152: typedef typename polymorphic_allocator<T>::size_type size_type;
153: typedef typename polymorphic_allocator<T>::difference_type difference_type;
154: typedef typename polymorphic_allocator<T>::pointer pointer;
155: typedef typename polymorphic_allocator<T>::const_pointer const_pointer;
156: typedef typename polymorphic_allocator<T>::reference reference;
157: typedef typename polymorphic_allocator<T>::const_reference const_reference;
158: typedef typename polymorphic_allocator<T>::value_type value_type;
159: //
160: logged_allocator() : polymorphic_allocator<T>() {__log_initialize(); __alloc_initialize();};
161: logged_allocator(const logged_allocator& a) : polymorphic_allocator<T>(a) {__log_initialize(); __alloc_initialize();};
162: template <class TT>
163: logged_allocator(const logged_allocator<TT>& aa) : polymorphic_allocator<T>(aa){__log_initialize(); __alloc_initialize();};
164: ~logged_allocator() {__alloc_finalize();};
165: // conversion typedef
166: template <class TT>
167: struct rebind { typedef logged_allocator<TT> other;};
169: T* allocate(size_type _n);
170: void deallocate(T* _p, size_type _n);
171: void construct(T* _p, const T& _val);
172: void destroy(T* _p);
174: T* create(const T& _val = T());
175: void del(T* _p);
176: template <class TT> void del(TT* _p, size_type _sz);
177: };
179: template <class T, bool O>
180: bool logged_allocator<T, O>::_log_initialized(false);
181: template <class T, bool O>
182: LogCookie logged_allocator<T,O>::_cookie(0);
183: template <class T, bool O>
184: int logged_allocator<T, O>::_allocate_event(0);
185: template <class T, bool O>
186: int logged_allocator<T, O>::_deallocate_event(0);
187: template <class T, bool O>
188: int logged_allocator<T, O>::_construct_event(0);
189: template <class T, bool O>
190: int logged_allocator<T, O>::_destroy_event(0);
191: template <class T, bool O>
192: int logged_allocator<T, O>::_create_event(0);
193: template <class T, bool O>
194: int logged_allocator<T, O>::_del_event(0);
195:
196: template <class T, bool O>
197: void logged_allocator<T, O>::__log_initialize() {
198: if(!logged_allocator::_log_initialized) {
199: // First of all we make sure PETSc is initialized
200: PetscTruth flag;
201: PetscErrorCode PetscInitialized(&flag); CHKERROR(ierr, "Error in PetscInitialized");
202: if(!flag) {
203: // I guess it would be nice to initialize PETSc here, but we'd need argv/argc here
204: throw ALE::Exception("PETSc not initialized");
205: }
206: // Get a new cookie based on the class name
207: const char *id_name = ALE::getClassName<T>();
208: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
209: // Use id_name to register a cookie and events.
210: logged_allocator::_cookie = LogCookieRegister(id_name);
211: // Register the basic allocator methods' invocations as events; use the mangled class name.
212: logged_allocator::_allocate_event = logged_allocator::__log_event_register(id_name, "allocate");
213: logged_allocator::_deallocate_event = logged_allocator::__log_event_register(id_name, "deallocate");
214: logged_allocator::_construct_event = logged_allocator::__log_event_register(id_name, "construct");
215: logged_allocator::_destroy_event = logged_allocator::__log_event_register(id_name, "destroy");
216: logged_allocator::_create_event = logged_allocator::__log_event_register(id_name, "create");
217: logged_allocator::_del_event = logged_allocator::__log_event_register(id_name, "del");
218: #endif
219: ALE::restoreClassName<T>(id_name);
220: logged_allocator::_log_initialized = true;
221: }// if(!!logged_allocator::_log_initialized)
222: }// logged_allocator<T,O>::__log_initialize()
224: template <class T, bool O>
225: void logged_allocator<T, O>::__alloc_initialize() {
226: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
227: const char *id_name = ALE::getClassName<T>();
228: PetscErrorCode PetscObjectCreateGeneric(PETSC_COMM_WORLD, logged_allocator::_cookie, id_name, &this->_petscObj);
229: CHKERROR(ierr, "Failed in PetscObjectCreate");
230: ALE::restoreClassName<T>(id_name);
231: #endif
232: }// logged_allocator<T,O>::__alloc_initialize
234: template <class T, bool O>
235: void logged_allocator<T, O>::__alloc_finalize() {
236: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
237: if (this->_petscObj) {
238: PetscErrorCode PetscObjectDestroy(this->_petscObj);
239: CHKERROR(ierr, "Failed in PetscObjectDestroy");
240: }
241: #endif
242: }// logged_allocator<T,O>::__alloc_finalize
244: template <class T, bool O>
245: LogEvent logged_allocator<T, O>::__log_event_register(const char *class_name, const char *event_name){
246: // This routine assumes a cookie has been obtained.
247: ostringstream txt;
248: if(O) {
249: txt << "Obj:";
250: }
251: #ifdef ALE_LOGGING_VERBOSE
252: txt << class_name;
253: #else
254: txt << "<allocator>";
255: #endif
256: txt << ":" << event_name;
257: return LogEventRegister(logged_allocator::_cookie, txt.str().c_str());
258: }
260: template <class T, bool O>
261: T* logged_allocator<T, O>::allocate(size_type _n) {
262: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
263: LogEventBegin(logged_allocator::_allocate_event);
264: #endif
265: T* _p = polymorphic_allocator<T>::allocate(_n);
266: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
267: PetscErrorCode PetscLogObjectMemory(this->_petscObj, _n*polymorphic_allocator<T>::sz);
268: CHKERROR(ierr, "Error in PetscLogObjectMemory");
269: LogEventEnd(logged_allocator::_allocate_event);
270: #endif
271: return _p;
272: }
273:
274: template <class T, bool O>
275: void logged_allocator<T, O>::deallocate(T* _p, size_type _n) {
276: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
277: LogEventBegin(logged_allocator::_deallocate_event);
278: #endif
279: polymorphic_allocator<T>::deallocate(_p, _n);
280: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
281: LogEventEnd(logged_allocator::_deallocate_event);
282: #endif
283: }
284:
285: template <class T, bool O>
286: void logged_allocator<T, O>::construct(T* _p, const T& _val) {
287: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
288: LogEventBegin(logged_allocator::_construct_event);
289: #endif
290: polymorphic_allocator<T>::construct(_p, _val);
291: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
292: LogEventEnd(logged_allocator::_construct_event);
293: #endif
294: }
295:
296: template <class T, bool O>
297: void logged_allocator<T, O>::destroy(T* _p) {
298: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
299: LogEventBegin(logged_allocator::_destroy_event);
300: #endif
301: polymorphic_allocator<T>::destroy(_p);
302: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
303: LogEventEnd(logged_allocator::_destroy_event);
304: #endif
305: }
306:
307: template <class T, bool O>
308: T* logged_allocator<T, O>::create(const T& _val) {
309: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
310: LogEventBegin(logged_allocator::_create_event);
311: #endif
312: T* _p = polymorphic_allocator<T>::create(_val);
313: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
314: PetscErrorCode PetscLogObjectMemory(this->_petscObj, polymorphic_allocator<T>::sz);
315: CHKERROR(ierr, "Error in PetscLogObjectMemory");
316: LogEventEnd(logged_allocator::_create_event);
317: #endif
318: return _p;
319: }
321: template <class T, bool O>
322: void logged_allocator<T, O>::del(T* _p) {
323: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
324: LogEventBegin(logged_allocator::_del_event);
325: #endif
326: polymorphic_allocator<T>::del(_p);
327: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
328: LogEventEnd(logged_allocator::_del_event);
329: #endif
330: }
332: template <class T, bool O> template <class TT>
333: void logged_allocator<T, O>::del(TT* _p, size_type _sz) {
334: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
335: LogEventBegin(logged_allocator::_del_event);
336: #endif
337: polymorphic_allocator<T>::del(_p, _sz);
338: #if defined ALE_USE_LOGGING && defined ALE_LOGGING_LOG_MEM
339: LogEventEnd(logged_allocator::_del_event);
340: #endif
341: }
343: #ifdef ALE_USE_LOGGING
344: #define ALE_ALLOCATOR ::ALE::logged_allocator
345: #else
346: #define ALE_ALLOCATOR ::ALE::polymorphic_allocator
347: #endif
349: //
350: // The following classes define smart pointer behavior.
351: // They rely on allocators for memory pooling and logging (if logging is on).
352: //
354: // This is an Obj<X>-specific exception that is thrown when incompatible object conversion is attempted.
355: class BadCast : public Exception {
356: public:
357: explicit BadCast(const string& msg) : Exception(msg) {};
358: explicit BadCast(const ostringstream& txt) : Exception(txt) {};
359: // It actually looks like passing txt as an argument to Exception(ostringstream) performs a copy of txt,
360: // which is disallowed due to the ostringstream constructor being private; must use a string constructor.
361: BadCast(const BadCast& e) : Exception(e) {};
362: };
364: // This is the main smart pointer class.
365: template<class X>
366: class Obj {
367: public:
368: // Types
369: #ifdef ALE_USE_LOGGING
370: typedef logged_allocator<X,true> Allocator;
371: typedef logged_allocator<int,true> Allocator_int;
372: #else
373: typedef polymorphic_allocator<X> Allocator;
374: typedef polymorphic_allocator<int> Allocator_int;
375: #endif
376: typedef typename Allocator::size_type size_type;
377: public:
378: // These are intended to be private or at least protected
379: // allocators
380: Allocator_int *int_allocator;
381: Allocator *allocator;
382: //
383: X* objPtr; // object pointer
384: int* refCnt; // reference count
385: size_type sz; // Size of underlying object (universal units) allocated with an allocator; indicates allocator use.
386: // Constructor; this can be made private, if we move operator Obj<Y> outside this class definition and make it a friend.
387: Obj(X *xx, int *refCnt, size_type sz);
388: public:
389: // Constructors & a destructor
390: Obj() : objPtr((X *)NULL), refCnt((int*)NULL), sz(0) {this->createAllocators();};
391: Obj(const X& x);
392: Obj(X *xx);
393: Obj(const Obj& obj);
394: virtual ~Obj();
396: // "Factory" methods
397: Obj& create(const X& x = X());
398: void destroy();
399: void createAllocators();
400: void destroyAllocators();
401: void handleAllocators(const bool);
403: // predicates & assertions
404: bool isNull() const {return (this->objPtr == NULL);};
405: void assertNull(bool flag) const { if(this->isNull() != flag){ throw(Exception("Null assertion failed"));}};
407: // comparison operators
408: bool operator==(const Obj& obj) { return (this->objPtr == obj.objPtr);};
409: bool operator!=(const Obj& obj) { return (this->objPtr != obj.objPtr);};
410:
411: // assignment/conversion operators
412: Obj& operator=(const Obj& obj);
413: template <class Y> operator Obj<Y> const();
414: template <class Y> Obj& operator=(const Obj<Y>& obj);
416: // dereference operators
417: X* operator->() const {return objPtr;};
418:
419: // "exposure" methods: expose the underlying object or object pointer
420: operator X*() {return objPtr;};
421: X& operator*() {assertNull(false); return *objPtr;};
422: operator X() {assertNull(false); return *objPtr;};
423: template<class Y> Obj& copy(const Obj<Y>& obj); // this operator will copy the underlying objects: USE WITH CAUTION
424:
426: // depricated methods/operators
427: X* ptr() {return objPtr;};
428: X* pointer() {return objPtr;};
429: X obj() {assertNull(false); return *objPtr;};
430: X object() {assertNull(false); return *objPtr;};
431:
432: };// class Obj<X>
434: // Constructors
435: // New reference
436: template <class X>
437: Obj<X>::Obj(const X& x) {
438: this->createAllocators();
439: this->refCnt = NULL;
440: this->create(x);
441: }
442:
443: // Stolen reference
444: template <class X>
445: Obj<X>::Obj(X *xx){// such an object will be destroyed by calling 'delete' on its pointer
446: // (e.g., we assume the pointer was obtained with new)
447: this->createAllocators();
448: if (xx) {
449: this->objPtr = xx;
450: this->refCnt = this->int_allocator->create(1);
451: //this->refCnt = new int(1);
452: this->sz = 0;
453: } else {
454: this->objPtr = NULL;
455: this->refCnt = NULL;
456: this->sz = 0;
457: }
458: }
459:
460: template <class X>
461: Obj<X>::Obj(X *_xx, int *_refCnt, size_type _sz) { // This is intended to be private.
462: this->createAllocators();
463: if (!_xx) {
464: throw ALE::Exception("Making an Obj with a NULL objPtr");
465: }
466: this->objPtr = _xx;
467: this->refCnt = _refCnt; // we assume that all refCnt pointers are obtained using an int_allocator
468: (*this->refCnt)++;
469: this->sz = _sz;
470: //if (!this->sz) {
471: // throw ALE::Exception("Making an Obj with zero size");
472: //}
473: }
474:
475: template <class X>
476: Obj<X>::Obj(const Obj& obj) {
477: this->createAllocators();
478: this->objPtr = obj.objPtr;
479: this->refCnt = obj.refCnt;
480: if (obj.refCnt) {
481: (*this->refCnt)++;
482: }
483: this->sz = obj.sz;
484: //if (!this->sz) {
485: // throw ALE::Exception("Making an Obj with zero size");
486: //}
487: }
489: // Destructor
490: template <class X>
491: Obj<X>::~Obj(){
492: this->destroy();
493: this->destroyAllocators();
494: }
496: template <class X>
497: void Obj<X>::createAllocators() {
498: this->handleAllocators(true);
499: }
501: template <class X>
502: void Obj<X>::destroyAllocators() {
503: this->handleAllocators(false);
504: }
506: template <class X>
507: void Obj<X>::handleAllocators(const bool create) {
508: static Allocator_int *s_int_allocator = NULL;
509: static Allocator *s_allocator = NULL;
510: static int s_allocRefCnt = 0;
512: if (create) {
513: if (s_allocRefCnt == 0) {
514: s_int_allocator = new Allocator_int();
515: s_allocator = new Allocator();
516: }
517: s_allocRefCnt++;
518: this->int_allocator = s_int_allocator;
519: this->allocator = s_allocator;
520: } else {
521: if (--s_allocRefCnt == 0) {
522: delete int_allocator;
523: delete allocator;
524: }
525: this->int_allocator = NULL;
526: this->allocator = NULL;
527: }
528: }
530: template <class X>
531: Obj<X>& Obj<X>::create(const X& x) {
532: // Destroy the old state
533: this->destroy();
534: // Create the new state
535: this->objPtr = this->allocator->create(x);
536: this->refCnt = this->int_allocator->create(1);
537: this->sz = this->allocator->sz;
538: if (!this->sz) {
539: throw ALE::Exception("Making an Obj with zero size obtained from allocator");
540: }
541: return *this;
542: }
544: template <class X>
545: void Obj<X>::destroy() {
546: if(ALE::getVerbosity() > 3) {
547: #ifdef ALE_USE_DEBUGGING
548: const char *id_name = ALE::getClassName<X>();
550: printf("Obj<X>.destroy: Destroying Obj<%s>", id_name);
551: if (!this->refCnt) {
552: printf(" with no refCnt\n");
553: } else {
554: printf(" with refCnt %d\n", *this->refCnt);
555: }
556: ALE::restoreClassName<X>(id_name);
557: #endif
558: }
559: if (this->refCnt != NULL) {
560: (*this->refCnt)--;
561: if (*this->refCnt == 0) {
562: // If allocator has been used to create an objPtr, as indicated by 'sz', we use the allocator to delete objPtr, using 'sz'.
563: if(this->sz != 0) {
564: #ifdef ALE_USE_DEBUGGING
565: if(ALE::getVerbosity() > 3) {
566: printf(" Calling deallocator on %p with size %d\n", this->objPtr, (int) this->sz);
567: }
568: #endif
569: this->allocator->del(this->objPtr, this->sz);
570: this->sz = 0;
571: }
572: else { // otherwise we use 'delete'
573: #ifdef ALE_USE_DEBUGGING
574: if(ALE::getVerbosity() > 3) {
575: printf(" Calling delete on %p\n", this->objPtr);
576: }
577: #endif
578: if (!this->objPtr) {
579: throw ALE::Exception("Trying to free NULL pointer");
580: }
581: delete this->objPtr;
582: }
583: // refCnt is always created/delete using the int_allocator.
584: this->int_allocator->del(this->refCnt);
585: this->objPtr = NULL;
586: this->refCnt = NULL;
587: }
588: }
589: }
591: // assignment operator
592: template <class X>
593: Obj<X>& Obj<X>::operator=(const Obj<X>& obj) {
594: if(this->objPtr == obj.objPtr) {return *this;}
595: // Destroy 'this' Obj -- it will properly release the underlying object if the reference count is exhausted.
596: if(this->objPtr) {
597: this->destroy();
598: }
599: // Now copy the data from obj.
600: this->objPtr = obj.objPtr;
601: this->refCnt = obj.refCnt;
602: if(this->refCnt!= NULL) {
603: (*this->refCnt)++;
604: }
605: this->sz = obj.sz;
606: return *this;
607: }
609: // conversion operator, preserves 'this'
610: template<class X> template<class Y>
611: Obj<X>::operator Obj<Y> const() {
612: // We attempt to cast X* objPtr to Y* using dynamic_
613: #ifdef ALE_USE_DEBUGGING
614: if(ALE::getVerbosity() > 1) {
615: printf("Obj<X>::operator Obj<Y>: attempting a dynamic_cast on objPtr %p\n", this->objPtr);
616: }
617: #endif
618: Y* yObjPtr = dynamic_cast<Y*>(this->objPtr);
619: // If the cast failed, throw an exception
620: if(yObjPtr == NULL) {
621: const char *Xname = ALE::getClassName<X>();
622: const char *Yname = ALE::getClassName<Y>();
623: std::string msg("Bad cast Obj<");
624: msg += Xname;
625: msg += "> --> Obj<";
626: msg += Yname;
627: msg += ">";
628: ALE::restoreClassName<X>(Xname);
629: ALE::restoreClassName<X>(Yname);
630: throw BadCast(msg.c_str());
631: }
632: // Okay, we can proceed
633: return Obj<Y>(yObjPtr, this->refCnt, this->sz);
634: }
636: // assignment-conversion operator
637: template<class X> template<class Y>
638: Obj<X>& Obj<X>::operator=(const Obj<Y>& obj) {
639: // We attempt to cast Y* obj.objPtr to X* using dynamic_cast
640: X* xObjPtr = dynamic_cast<X*>(obj.objPtr);
641: // If the cast failed, throw an exception
642: if(xObjPtr == NULL) {
643: const char *Xname = ALE::getClassName<X>();
644: const char *Yname = ALE::getClassName<Y>();
645: std::string msg("Bad assignment cast Obj<");
646: msg += Yname;
647: msg += "> --> Obj<";
648: msg += Xname;
649: msg += ">";
650: ALE::restoreClassName<X>(Xname);
651: ALE::restoreClassName<X>(Yname);
652: throw BadCast(msg.c_str());
653: }
654: // Okay, we can proceed with the assignment
655: if(this->objPtr == obj.objPtr) {return *this;}
656: // Destroy 'this' Obj -- it will properly release the underlying object if the reference count is exhausted.
657: this->destroy();
658: // Now copy the data from obj.
659: this->objPtr = xObjPtr;
660: this->refCnt = obj.refCnt;
661: (*this->refCnt)++;
662: this->sz = obj.sz;
663: return *this;
664: }
665:
666: // copy operator (USE WITH CAUTION)
667: template<class X> template<class Y>
668: Obj<X>& Obj<X>::copy(const Obj<Y>& obj) {
669: if(this->isNull() || obj.isNull()) {
670: throw(Exception("Copying to or from a null Obj"));
671: }
672: *(this->objPtr) = *(obj.objPtr);
673: return *this;
674: }
677: } // namespace ALE
679: #endif