Here is yet another example of my overbearing tendency to tackle new projects without enough planning. This is my constantly-in-development money managing program. I recently tried to implement a logging system (line saved in file for ever deposit/withdrawl) with what I though was great success until... It happened. I don't know what went wrong, but as you will see in the code, there comes an error in this fashion: main() -> CommandSwitch() -> loadfile() -> ReadInAccounts() ->(in the log case) SaveAccount() -> ACCNT::~ACCNT() -> array<string>::~array<string>() -> basic_string::vector deleting destructor -> operator delete(void*) -> free(void*) -> UNHANDLED EXCEPTION ERROR: CRASH.
This object is the culprit: array<string> log;
I know this must have something to do with deleting unallocated data, or acessing deleted data or SOMETHING. I just can't find where. Any line followed by '//DEBUG' in my code is just for debugging purposes.
Any ideas are appreciated. HERE'S A CODE DUMP. I excluded most of the code as to save anybody who's willing to read any. The problemed parts are bolded: (problemed, according to MSVC++ 6 debugger)
Code:ACCNT::~ACCNT() { } int ACCNT::operator =(ACCNT other) { withdraw(-1,NULL,true); deposit(other.GetBalance(),NULL,true); label(other.GetName()); SetIDNumber(other.GetIDNumber()); SetAccountNum(other.GetAccountNum()); if(other.GetNumLogEntries() == 0) Log.purge(); else { cout << other.GetLog()[0] << endl; //DEBUG //Log = other.GetLog(); } return 1; } array<string> & ACCNT::GetLog() { return Log; } BANK::BANK() { AccountPointer = 0; full = false; edited = false; NumOfAccounts = 0; for(int x = 0; x < MAX_NUM_ACCOUNTS; x++) { AccountsMap[x] = 0; } } int BANK::SaveAccount(ACCNT InputAccount, bool UsedInCreation) { cout << InputAccount.GetName() << endl;//DEBUG if(!UsedInCreation) { if(!edited) edited = true; } if(AccountsMap[InputAccount.GetIDNumber()] == 0) return -1; else if(AccountsMap[InputAccount.GetIDNumber()] == 1) { cout << "Inside Save account: going to use = operator" << endl;//DEBUG Accounts[InputAccount.GetIDNumber()] = InputAccount; cout << "Done equalizing" << endl;//DEBUG } else return -1; return 0; } int BANK::ReadInAccounts(const char* FileName,bool purgeAccounts) { SCRIPT_POSITION read_state = ACC_NUM; char buffer[1024]; ifstream Reader(FileName); bool active = true; ACCNT CurrentAccount; if(purgeAccounts) purge(); if(Reader.fail()) return -1; while(active) { switch(read_state) { case ACC_NUM: { Reader.getline(buffer,1024); if(Reader.eof()) { active = false; break; } if(strlen(buffer) > 2) { if(buffer[0] == '/' && buffer[1] == '/') continue; } CurrentAccount = CreateAccount(atoi(buffer),0,"~null~"); read_state = NAME; }break; case NAME: { Reader.getline(buffer,1024); if(Reader.eof()) { active = false; break; } if(strlen(buffer) > 2) { if(buffer[0] == '/' && buffer[1] == '/') continue; } CurrentAccount.label(buffer); SaveAccount(CurrentAccount,true); read_state = MONEY; }break; case MONEY: { Reader.getline(buffer,1024); if(Reader.eof()) { active = false; break; } if(strlen(buffer) > 2) { if(buffer[0] == '/' && buffer[1] == '/') continue; } CurrentAccount.deposit(atof(buffer),"Creation",true); SaveAccount(CurrentAccount,true); read_state = LOG; }break; case LOG: { cout << "Log reader" << endl;//DEBUG Reader.getline(buffer,1024); cout << "Read log line" << endl;//DEBUG //DEBUG if(Reader.eof()) { active = false; break; } if(strlen(buffer) > 2) { if(buffer[0] == '/' && buffer[1] == '/') continue; } if(!strcmpi(buffer,"ENDLOG")) { cout << "Endlog found" << endl;//DEBUG read_state = ACC_NUM; break; } else { cout << "Going to add entry" << endl; //DEBUG CurrentAccount.AddLogEntry(buffer); cout << "Added Entry\nGoing to save account." << endl;//DEBUG if(CurrentAccount.GetNumLogEntries() > 0)//debug cout << "Data at ReadInAccounts(): " << CurrentAccount.GetLogEntry(CurrentAccount.GetNumLogEntries() - 1) << endl;//debug SaveAccount(CurrentAccount,true); cout << "Account Saved" << endl;//DEBUG } //Log entry example: //Thu Jan 16 12:44:01 1998~1045.66~WITHDRAW 45.66~1000~Ordered lots of pizza }break; default: { }break; } } return 0; } void ACCNT::AddLogEntry(string entry) { Log.resize(Log.GetSize() + 1); Log[Log.GetSize() - 1] = entry; } string ACCNT::GetLogEntry(int index) { return (index > Log.GetSize() && index >= 0) ? "~ERROR~" : Log[index]; }Code://ARRAYCL.H - a template that allows users to pass arrays as variables// ///(a.k.a. CodeMonkey's custom vector)//////////////////////////////// #ifndef _ARRAYCL_H #define _ARRAYCL_H template <class T> class array { public: array(int input_size) { size = input_size; Data = new T[input_size]; } array() { size = 0; Data = NULL; } void purge() { size = 0; delete [] Data; } ~array() { delete [] Data; } T & operator [] (int index) { if(index >= 0 && index <= size) return Data[index]; else exit(1); } operator T*() { return Data; } const T & operator [] (int index) const { if(index >= 0 && index <= size) return Data[index]; else exit(1); } const array & operator = (const array<typename T> & other) { if(this != &other) { delete [] Data; size = other.GetSize(); Data = new T[size]; for(int x = 0; x < size; x++) Data[x] = other[x]; } return *this; } int GetSize() const { return size; } void resize(int newSize) { int numToCopy = newSize < size ? newSize : size; //First time I used this operator: HAH! T * newData = new T[newSize]; for(int x = 0; x < numToCopy; x++) { newData[x] = Data[x]; } delete [] Data; size = newSize; Data = newData; } protected: int size; T* Data; }; #endifCode://Class that holds an array of strings and can convert string to strings, etc. //All done by David Goffredo (CodeMonkey), October 22, 2003 //Requires the "array class", a custom vector template I made. #ifndef _SENTENCE_H #define _SENTENCE_H //#define TRUE_SENT If you want a sentence to end at punctuation: // turn off if you will be using punctuation // for non-gramatical purposes (command-line, etc.) #include <string> #include <arraycl.h> using namespace std; struct _SentenceType { bool exclamatory; bool declarative; bool interrogative; bool imperitive; void reset() { exclamatory = declarative = interrogative = imperitive = false; } }; typedef _SentenceType SentenceType; class sentence : public array<string> { public: sentence(int numWords) { size = numWords; Data = new string[numWords]; type.reset(); } sentence() { size = 0; Data = NULL; type.reset(); } sentence(string value) { size = 0; BreakDown(value); type.reset(); } int BreakDown(string s_input) { short int* where = new short int[s_input.length() +1]; short int where_place = 0; for(int x = 0; x <= s_input.length() + 1; x++) { if(s_input[x] == ' ') { where[where_place] = x; where_place++; } else if(s_input[x] == '\0' #ifdef TRUE_SENT || s_input[x] == '.' || s_input[x] == '?' || s_input[x] == '!' #endif ) { where[where_place] = x; where[where_place +1] = -1; where_place++; break; } } resize(where_place); if(where_place < 1) Data[0] = s_input.substr(0,where[where_place]); else if(where[where_place] == s_input.length() + 1) where_place--; else { Data[0] = s_input.substr(0,where[0]); for(int y = 0; y < where_place - 1; y++) { Data[y + 1] = s_input.substr(where[y] + 1, where[y + 1] - (where[y] + 1) ); } } return 0; } string print(bool end_punctuation) { string ReturnValue; for(int x = 0; x < size; x ++) { if(x > 0) ReturnValue += " "; ReturnValue += Data[x]; } if(end_punctuation) { if( (type.declarative + type.imperitive + type.interrogative + type.exclamatory) > 0) { if( (type.declarative || type.imperitive) && type.interrogative) { ReturnValue += " "; } else if(type.exclamatory) { if(type.interrogative) { ReturnValue += "?!"; } else ReturnValue += "!"; } else if(type.declarative || type.imperitive) ReturnValue += "."; else if(type.interrogative) ReturnValue += "?"; } else ReturnValue += " "; } return ReturnValue; } int numOfWords() const { return size; } SentenceType type; }; #endif



LinkBack URL
About LinkBacks


