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() const {return objPtr;};
428: X* pointer() const {return objPtr;};
429: X obj() const {assertNull(false); return *objPtr;};
430: X object() const {assertNull(false); return *objPtr;};
432: void addRef() {if (refCnt) {(*refCnt)++;}}
433: };// class Obj<X>
435: // Constructors
436: // New reference
437: template <class X>
438: Obj<X>::Obj(const X& x) {
439: this->createAllocators();
440: this->refCnt = NULL;
441: this->create(x);
442: }
443:
444: // Stolen reference
445: template <class X>
446: Obj<X>::Obj(X *xx){// such an object will be destroyed by calling 'delete' on its pointer
447: // (e.g., we assume the pointer was obtained with new)
448: this->createAllocators();
449: if (xx) {
450: this->objPtr = xx;
451: this->refCnt = this->int_allocator->create(1);
452: //this->refCnt = new int(1);
453: this->sz = 0;
454: } else {
455: this->objPtr = NULL;
456: this->refCnt = NULL;
457: this->sz = 0;
458: }
459: }
460:
461: template <class X>
462: Obj<X>::Obj(X *_xx, int *_refCnt, size_type _sz) { // This is intended to be private.
463: this->createAllocators();
464: if (!_xx) {
465: throw ALE::Exception("Making an Obj with a NULL objPtr");
466: }
467: this->objPtr = _xx;
468: this->refCnt = _refCnt; // we assume that all refCnt pointers are obtained using an int_allocator
469: (*this->refCnt)++;
470: this->sz = _sz;
471: //if (!this->sz) {
472: // throw ALE::Exception("Making an Obj with zero size");
473: //}
474: }
475:
476: template <class X>
477: Obj<X>::Obj(const Obj& obj) {
478: this->createAllocators();
479: this->objPtr = obj.objPtr;
480: this->refCnt = obj.refCnt;
481: if (obj.refCnt) {
482: (*this->refCnt)++;
483: }
484: this->sz = obj.sz;
485: //if (!this->sz) {
486: // throw ALE::Exception("Making an Obj with zero size");
487: //}
488: }
490: // Destructor
491: template <class X>
492: Obj<X>::~Obj(){
493: this->destroy();
494: this->destroyAllocators();
495: }
497: template <class X>
498: void Obj<X>::createAllocators() {
499: this->handleAllocators(true);
500: }
502: template <class X>
503: void Obj<X>::destroyAllocators() {
504: this->handleAllocators(false);
505: }
507: template <class X>
508: void Obj<X>::handleAllocators(const bool create) {
509: static Allocator_int *s_int_allocator = NULL;
510: static Allocator *s_allocator = NULL;
511: static int s_allocRefCnt = 0;
513: if (create) {
514: if (s_allocRefCnt == 0) {
515: s_int_allocator = new Allocator_int();
516: s_allocator = new Allocator();
517: }
518: s_allocRefCnt++;
519: this->int_allocator = s_int_allocator;
520: this->allocator = s_allocator;
521: } else {
522: if (--s_allocRefCnt == 0) {
523: delete int_allocator;
524: delete allocator;
525: }
526: this->int_allocator = NULL;
527: this->allocator = NULL;
528: }
529: }
531: template <class X>
532: Obj<X>& Obj<X>::create(const X& x) {
533: // Destroy the old state
534: this->destroy();
535: // Create the new state
536: this->objPtr = this->allocator->create(x);
537: this->refCnt = this->int_allocator->create(1);
538: this->sz = this->allocator->sz;
539: if (!this->sz) {
540: throw ALE::Exception("Making an Obj with zero size obtained from allocator");
541: }
542: return *this;
543: }
545: template <class X>
546: void Obj<X>::destroy() {
547: if(ALE::getVerbosity() > 3) {
548: #ifdef ALE_USE_DEBUGGING
549: const char *id_name = ALE::getClassName<X>();
551: printf("Obj<X>.destroy: Destroying Obj<%s>", id_name);
552: if (!this->refCnt) {
553: printf(" with no refCnt\n");
554: } else {
555: printf(" with refCnt %d\n", *this->refCnt);
556: }
557: ALE::restoreClassName<X>(id_name);
558: #endif
559: }
560: if (this->refCnt != NULL) {
561: (*this->refCnt)--;
562: if (*this->refCnt == 0) {
563: // If allocator has been used to create an objPtr, as indicated by 'sz', we use the allocator to delete objPtr, using 'sz'.
564: if(this->sz != 0) {
565: #ifdef ALE_USE_DEBUGGING
566: if(ALE::getVerbosity() > 3) {
567: printf(" Calling deallocator on %p with size %d\n", this->objPtr, (int) this->sz);
568: }
569: #endif
570: this->allocator->del(this->objPtr, this->sz);
571: this->sz = 0;
572: }
573: else { // otherwise we use 'delete'
574: #ifdef ALE_USE_DEBUGGING
575: if(ALE::getVerbosity() > 3) {
576: printf(" Calling delete on %p\n", this->objPtr);
577: }
578: #endif
579: if (!this->objPtr) {
580: throw ALE::Exception("Trying to free NULL pointer");
581: }
582: delete this->objPtr;
583: }
584: // refCnt is always created/delete using the int_allocator.
585: this->int_allocator->del(this->refCnt);
586: this->objPtr = NULL;
587: this->refCnt = NULL;
588: }
589: }
590: }
592: // assignment operator
593: template <class X>
594: Obj<X>& Obj<X>::operator=(const Obj<X>& obj) {
595: if(this->objPtr == obj.objPtr) {return *this;}
596: // Destroy 'this' Obj -- it will properly release the underlying object if the reference count is exhausted.
597: if(this->objPtr) {
598: this->destroy();
599: }
600: // Now copy the data from obj.
601: this->objPtr = obj.objPtr;
602: this->refCnt = obj.refCnt;
603: if(this->refCnt!= NULL) {
604: (*this->refCnt)++;
605: }
606: this->sz = obj.sz;
607: return *this;
608: }
610: // conversion operator, preserves 'this'
611: template<class X> template<class Y>
612: Obj<X>::operator Obj<Y> const() {
613: // We attempt to cast X* objPtr to Y* using dynamic_
614: #ifdef ALE_USE_DEBUGGING
615: if(ALE::getVerbosity() > 1) {
616: printf("Obj<X>::operator Obj<Y>: attempting a dynamic_cast on objPtr %p\n", this->objPtr);
617: }
618: #endif
619: Y* yObjPtr = dynamic_cast<Y*>(this->objPtr);
620: // If the cast failed, throw an exception
621: if(yObjPtr == NULL) {
622: const char *Xname = ALE::getClassName<X>();
623: const char *Yname = ALE::getClassName<Y>();
624: std::string msg("Bad cast Obj<");
625: msg += Xname;
626: msg += "> --> Obj<";
627: msg += Yname;
628: msg += ">";
629: ALE::restoreClassName<X>(Xname);
630: ALE::restoreClassName<X>(Yname);
631: throw BadCast(msg.c_str());
632: }
633: // Okay, we can proceed
634: return Obj<Y>(yObjPtr, this->refCnt, this->sz);
635: }
637: // assignment-conversion operator
638: template<class X> template<class Y>
639: Obj<X>& Obj<X>::operator=(const Obj<Y>& obj) {
640: // We attempt to cast Y* obj.objPtr to X* using dynamic_cast
641: X* xObjPtr = dynamic_cast<X*>(obj.objPtr);
642: // If the cast failed, throw an exception
643: if(xObjPtr == NULL) {
644: const char *Xname = ALE::getClassName<X>();
645: const char *Yname = ALE::getClassName<Y>();
646: std::string msg("Bad assignment cast Obj<");
647: msg += Yname;
648: msg += "> --> Obj<";
649: msg += Xname;
650: msg += ">";
651: ALE::restoreClassName<X>(Xname);
652: ALE::restoreClassName<X>(Yname);
653: throw BadCast(msg.c_str());
654: }
655: // Okay, we can proceed with the assignment
656: if(this->objPtr == obj.objPtr) {return *this;}
657: // Destroy 'this' Obj -- it will properly release the underlying object if the reference count is exhausted.
658: this->destroy();
659: // Now copy the data from obj.
660: this->objPtr = xObjPtr;
661: this->refCnt = obj.refCnt;
662: (*this->refCnt)++;
663: this->sz = obj.sz;
664: return *this;
665: }
666:
667: // copy operator (USE WITH CAUTION)
668: template<class X> template<class Y>
669: Obj<X>& Obj<X>::copy(const Obj<Y>& obj) {
670: if(this->isNull() || obj.isNull()) {
671: throw(Exception("Copying to or from a null Obj"));
672: }
673: *(this->objPtr) = *(obj.objPtr);
674: return *this;
675: }
678: } // namespace ALE
680: #endif