/// \ingroup rbd_common ///@{ /// \file myexcept.cpp /// Exception handler. /// The low level classes for /// - my exception class hierarchy /// - the functions needed for my simulated exceptions /// - the Tracer mechanism /// - routines for checking whether new and delete calls are balanced /// // Copyright (C) 1993,4,6: R B Davies #define WANT_STREAM // include.h will get stream fns #define WANT_STRING #include "include.h" // include standard files #include "myexcept.h" // for exception handling #include "newmat.h" // for exception handling #ifdef use_namespace namespace RBD_COMMON { #endif #ifdef USE_STD_NAMESPACE using namespace std; #endif //#define REG_DEREG // for print out uses of new/delete //#define CLEAN_LIST // to print entries being added to // or deleted from cleanup list #ifdef SimulateExceptions void Throw() { for (Janitor* jan = JumpBase::jl->janitor; jan; jan = jan->NextJanitor) jan->CleanUp(); JumpItem* jx = JumpBase::jl->ji; // previous jumpbase; if ( !jx ) { Terminate(); } // jl was initial JumpItem JumpBase::jl = jx; // drop down a level; cannot be in front // of previous line Tracer::last = JumpBase::jl->trace; longjmp(JumpBase::jl->env, 1); } #endif // end of simulate exceptions BaseException::BaseException(const char* a_what) { _what = new char[MAXSIZE]; if (!_what) { // fail to make space _what = (char *)"No heap space for exception message\n"; _deleteMe = false; } else { _deleteMe = true; } AddMessage("\n\nAn exception has been thrown\n"); AddMessage(a_what); } BaseException::BaseException(const BaseException& oth) { _what = new char[MAXSIZE]; if (!_what) { // fail to make space _what = (char *)"No heap space for exception message\n"; _deleteMe = false; } else { _deleteMe = true; strcpy(_what, oth._what); } } BaseException& BaseException::operator=(const BaseException& oth) { if (this == &oth) return *this; _what = new char[MAXSIZE]; if (!_what) { // fail to make space _what = (char *)"No heap space for exception message\n"; _deleteMe = false; } else { _deleteMe = true; strcpy(_what, oth._what); } return *this; } BaseException::~BaseException() { if (_deleteMe) delete[] _what; } void BaseException::AddMessage(const char* a_what) { if (a_what) { size_t nn = MAXSIZE - strlen(_what) - 1; strncat(_what, a_what, nn); } } void BaseException::AddInt(int value) { bool negative = false; if (value == 0) { AddMessage("0"); return; } else if (value < 0) { value = -value; negative = true; } int nn = (negative ? 1 : 0); // how many digits will we need? int vv = value; while (vv > 0) { vv /= 10; ++nn; } if ((int)(MAXSIZE - strlen(_what)) < nn) { AddMessage("***"); return; } nn += strlen(_what); _what[nn] = 0; while (value > 0) { int nv = value / 10; int rm = value - nv * 10; value = nv; _what[--nn] = (char)(rm + '0'); } if (negative) _what[--nn] = '-'; } void BaseException::MatrixDetails(const GeneralMatrix& A) { MatrixBandWidth bw = A.bandwidth(); int ubw = bw.upper_val; int lbw = bw.lower_val; AddMessage("MatrixType = "); AddMessage(A.Type().Value()); AddMessage(" # Rows = "); BaseException::AddInt(A.Nrows()); AddMessage("; # Cols = "); BaseException::AddInt(A.Ncols()); if (lbw >=0) { AddMessage("; lower BW = "); AddInt(lbw); } if (ubw >=0) { AddMessage("; upper BW = "); AddInt(ubw); } AddMessage("\n"); } #ifdef SimulateExceptions Janitor::Janitor() { if (do_not_link) { do_not_link = false; NextJanitor = 0; OnStack = false; #ifdef CLEAN_LIST cout << "Not added to clean-list " << (unsigned long)this << "\n"; #endif } else { OnStack = true; #ifdef CLEAN_LIST cout << "Add to clean-list " << (unsigned long)this << "\n"; #endif NextJanitor = JumpBase::jl->janitor; JumpBase::jl->janitor=this; } } Janitor::~Janitor() { // expect the item to be deleted to be first on list // but must be prepared to search list if (OnStack) { #ifdef CLEAN_LIST cout << "Delete from clean-list " << (unsigned long)this << "\n"; #endif Janitor* lastjan = JumpBase::jl->janitor; if (this == lastjan) JumpBase::jl->janitor = NextJanitor; else { for (Janitor* jan = lastjan->NextJanitor; jan; jan = lastjan->NextJanitor) { if (jan==this) { lastjan->NextJanitor = jan->NextJanitor; return; } lastjan=jan; } Throw(BaseException( "Cannot resolve memory linked list\nSee notes in myexcept.cpp for details\n" )); // This message occurs when a call to ~Janitor() occurs, apparently // without a corresponding call to Janitor(). This could happen if my // way of deciding whether a constructor is being called by new // fails. // It may happen if you are using my simulated exceptions and also have // your compiler s exceptions turned on. // It can also happen if you have a class derived from Janitor // which does not include a copy constructor [ eg X(const &X) ]. // Possibly also if delete is applied an object on the stack (ie not // called by new). Otherwise, it is a bug in myexcept or your compiler. // If you do not #define TEMPS_DESTROYED_QUICKLY you will get this // error with Microsoft C 7.0. There are probably situations where // you will get this when you do define TEMPS_DESTROYED_QUICKLY. This // is a bug in MSC. Beware of "operator" statements for defining // conversions; particularly for converting from a Base class to a // Derived class. // You may get away with simply deleting this error message and Throw // statement if you can not find a better way of overcoming the // problem. In any case please tell me if you get this error message, // particularly for compilers apart from Microsoft C 7.0. } } } JumpItem* JumpBase::jl; // will be set to zero jmp_buf JumpBase::env; bool Janitor::do_not_link; // will be set to false int JanitorInitializer::ref_count; JanitorInitializer::JanitorInitializer() { if (ref_count++ == 0) new JumpItem; // need JumpItem at head of list } #endif // end of SimulateExceptions Tracer* Tracer::last; // will be set to zero void Terminate() { cout << "\n\nThere has been an exception with no handler - exiting"; exit(1); } #ifdef DO_FREE_CHECK // Routines for tracing whether new and delete calls are balanced FreeCheckLink::FreeCheckLink() : next(FreeCheck::next) { FreeCheck::next = this; } FCLClass::FCLClass(void* t, char* name) : ClassName(name) { ClassStore=t; } FCLRealArray::FCLRealArray(void* t, char* o, int s) : Operation(o), size(s) { ClassStore=t; } FCLIntArray::FCLIntArray(void* t, char* o, int s) : Operation(o), size(s) { ClassStore=t; } FreeCheckLink* FreeCheck::next; int FreeCheck::BadDelete; void FCLClass::Report() { cout << " " << ClassName << " " << (unsigned long)ClassStore << "\n"; } void FCLRealArray::Report() { cout << " " << Operation << " " << (unsigned long)ClassStore << " " << size << "\n"; } void FCLIntArray::Report() { cout << " " << Operation << " " << (unsigned long)ClassStore << " " << size << "\n"; } void FreeCheck::Register(void* t, char* name) { FCLClass* f = new FCLClass(t,name); if (!f) { cout << "Out of memory in FreeCheck\n"; exit(1); } #ifdef REG_DEREG cout << "Registering " << name << " " << (unsigned long)t << "\n"; #endif } void FreeCheck::RegisterR(void* t, char* o, int s) { FCLRealArray* f = new FCLRealArray(t,o,s); if (!f) { cout << "Out of memory in FreeCheck\n"; exit(1); } #ifdef REG_DEREG cout << o << " " << s << " " << (unsigned long)t << "\n"; #endif } void FreeCheck::RegisterI(void* t, char* o, int s) { FCLIntArray* f = new FCLIntArray(t,o,s); if (!f) { cout << "Out of memory in FreeCheck\n"; exit(1); } #ifdef REG_DEREG cout << o << " " << s << " " << (unsigned long)t << "\n"; #endif } void FreeCheck::DeRegister(void* t, char* name) { FreeCheckLink* last = 0; #ifdef REG_DEREG cout << "Deregistering " << name << " " << (unsigned long)t << "\n"; #endif for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next) { if (fcl->ClassStore==t) { if (last) last->next = fcl->next; else next = fcl->next; delete fcl; return; } last = fcl; } cout << "\nRequest to delete non-existent object of class and location:\n"; cout << " " << name << " " << (unsigned long)t << "\n"; BadDelete++; Tracer::PrintTrace(); cout << "\n"; } void FreeCheck::DeRegisterR(void* t, char* o, int s) { FreeCheckLink* last = 0; #ifdef REG_DEREG cout << o << " " << s << " " << (unsigned long)t << "\n"; #endif for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next) { if (fcl->ClassStore==t) { if (last) last->next = fcl->next; else next = fcl->next; if (s >= 0 && ((FCLRealArray*)fcl)->size != s) { cout << "\nArray sizes do not agree:\n"; cout << " " << o << " " << (unsigned long)t << " " << ((FCLRealArray*)fcl)->size << " " << s << "\n"; Tracer::PrintTrace(); cout << "\n"; } delete fcl; return; } last = fcl; } cout << "\nRequest to delete non-existent real array:\n"; cout << " " << o << " " << (unsigned long)t << " " << s << "\n"; BadDelete++; Tracer::PrintTrace(); cout << "\n"; } void FreeCheck::DeRegisterI(void* t, char* o, int s) { FreeCheckLink* last = 0; #ifdef REG_DEREG cout << o << " " << s << " " << (unsigned long)t << "\n"; #endif for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next) { if (fcl->ClassStore==t) { if (last) last->next = fcl->next; else next = fcl->next; if (s >= 0 && ((FCLIntArray*)fcl)->size != s) { cout << "\nArray sizes do not agree:\n"; cout << " " << o << " " << (unsigned long)t << " " << ((FCLIntArray*)fcl)->size << " " << s << "\n"; Tracer::PrintTrace(); cout << "\n"; } delete fcl; return; } last = fcl; } cout << "\nRequest to delete non-existent int array:\n"; cout << " " << o << " " << (unsigned long)t << " " << s << "\n"; BadDelete++; Tracer::PrintTrace(); cout << "\n"; } void FreeCheck::Status() { if (next) { cout << "\nObjects of the following classes remain undeleted:\n"; for (FreeCheckLink* fcl = next; fcl; fcl = fcl->next) fcl->Report(); cout << "\n"; } else cout << "\nNo objects remain undeleted\n\n"; if (BadDelete) { cout << "\nThere were " << BadDelete << " requests to delete non-existent items\n\n"; } } #endif // end of DO_FREE_CHECK // derived exception bodies Logic_error::Logic_error(const char* a_what) : BaseException() { Select = BaseException::Select; AddMessage("Logic error:- "); AddMessage(a_what); if (a_what) Tracer::AddTrace(); } Runtime_error::Runtime_error(const char* a_what) : BaseException() { Select = BaseException::Select; AddMessage("Runtime error:- "); AddMessage(a_what); if (a_what) Tracer::AddTrace(); } Domain_error::Domain_error(const char* a_what) : Logic_error() { Select = BaseException::Select; AddMessage("domain error\n"); AddMessage(a_what); if (a_what) Tracer::AddTrace(); } Invalid_argument::Invalid_argument(const char* a_what) : Logic_error() { Select = BaseException::Select; AddMessage("invalid argument\n"); AddMessage(a_what); if (a_what) Tracer::AddTrace(); } Length_error::Length_error(const char* a_what) : Logic_error() { Select = BaseException::Select; AddMessage("length error\n"); AddMessage(a_what); if (a_what) Tracer::AddTrace(); } Out_of_range::Out_of_range(const char* a_what) : Logic_error() { Select = BaseException::Select; AddMessage("out of range\n"); AddMessage(a_what); if (a_what) Tracer::AddTrace(); } //Bad_cast::Bad_cast(const char* a_what) : Logic_error() //{ // Select = BaseException::Select; // AddMessage("bad cast\n"); AddMessage(a_what); // if (a_what) Tracer::AddTrace(); //} //Bad_typeid::Bad_typeid(const char* a_what) : Logic_error() //{ // Select = BaseException::Select; // AddMessage("bad type id.\n"); AddMessage(a_what); // if (a_what) Tracer::AddTrace(); //} Range_error::Range_error(const char* a_what) : Runtime_error() { Select = BaseException::Select; AddMessage("range error\n"); AddMessage(a_what); if (a_what) Tracer::AddTrace(); } Overflow_error::Overflow_error(const char* a_what) : Runtime_error() { Select = BaseException::Select; AddMessage("overflow error\n"); AddMessage(a_what); if (a_what) Tracer::AddTrace(); } Bad_alloc::Bad_alloc(const char* a_what) : BaseException() { Select = BaseException::Select; AddMessage("bad allocation\n"); AddMessage(a_what); if (a_what) Tracer::AddTrace(); } unsigned long BaseException::Select; unsigned long Logic_error::Select; unsigned long Runtime_error::Select; unsigned long Domain_error::Select; unsigned long Invalid_argument::Select; unsigned long Length_error::Select; unsigned long Out_of_range::Select; //unsigned long Bad_cast::Select; //unsigned long Bad_typeid::Select; unsigned long Range_error::Select; unsigned long Overflow_error::Select; unsigned long Bad_alloc::Select; #ifdef use_namespace } #endif ///@}