stl containers disappear

Z

zero

First a short discription of my program. I have a bot that connects to
an internet chess server. Whenever the bot logs on, it loads certain
information from file, and puts it in STL containers (specifically sets &
maps). When disconnecting for any reason, the containers are converted
to strings, and saved to disk, so they can be loaded again when the bot
logs back on. Periodically (triggered by a timer event), the bot mails a
log to addresses contained in two of the maps. The same timer is used to
send the output buffer to the server (such a buffer is needed because if
you send too much data at once, the server closes the connection as a
security precaution). There is also a mechanism that automatically re-
connects the bot if it is disconnected.

Now the problem. If the bot disconnects a few times, the log gets mailed
normally the first time, but the next time it should be sent, all the
containters are empty! This of course means the log can't be sent,
'cause it gets the mail addresses from two of the containers. I have no
idea how or why this happens.

I'd appreciate any ideas on how to fix this.


Here are some parts of the code:


typedef std::map<AnsiString, int, myless> guideMap;
typedef std::map<AnsiString, AnsiString, myless> adrMap;
typedef std::set<AnsiString> headSet;

class GuideBot :public CNBot
{
private:
int assistsAsked;
int unansweredAssists;
int guestAssists;
guideMap theGuides;
guideMap theAdmins;
headSet theTDHeads;
adrMap theAAdr;
adrMap theGAdr;

void handleLevel1Block();
void processTell(AnsiString tellFrom, AnsiString theTell, UINT type);
void findGAlias(AnsiString tellFrom, AnsiString theTell);
void findTDAlias(AnsiString tellFrom, AnsiString theTell);
void findAAlias(AnsiString tellFrom, AnsiString theTell);
void loadAll();
bool isHead(AnsiString user);
bool isGHead(AnsiString user);
bool isAHead(AnsiString user);
bool isTDHead(AnsiString user);

public:
GuideBot():CNBot() {}
GuideBot(AnsiString asHandle, AnsiString asPassword):CNBot(asHandle,
asPassword) {}
GuideBot(AnsiString asFileName, TClientSocket *tcsConnection):CNBot
(asFileName, tcsConnection) {}
GuideBot(AnsiString asFileName, TClientSocket *tcsConnection,
AnsiString asSection):CNBot(asFileName, tcsConnection, asSection) {}
~GuideBot() {}

void onConnect(TCustomWinSocket *Socket);
void saveAll();
void mailDump();
int countingSince;
};

void __fastcall TForm1::ClientSocketConnect(TObject *Sender,
TCustomWinSocket *Socket)
{
Bot->onConnect(Socket);
HandleEdit->Enabled = false;
PasswordEdit->Enabled = false;
CommandEdit->Enabled = true;
if(Application->ShowMainForm)
CommandEdit->SetFocus();
TrayMessage(NIM_MODIFY);
}

void __fastcall TForm1::ClientSocketDisconnect(TObject *Sender,
TCustomWinSocket *Socket)
{
Output->Lines->Add("**** DISCONNECTED ****");
HandleEdit->Enabled = true;
PasswordEdit->Enabled = true;
CommandEdit->Enabled = false;
Bot->saveAll();
if(Bot->stayConnected)
{
reconnectValue = 4000;
reconnectTimer = 0;
}
TrayMessage(NIM_MODIFY);
}

void __fastcall TForm1::ClientSocketError(TObject *Sender,
TCustomWinSocket *Socket, TErrorEvent ErrorEvent, int &ErrorCode)
{
Bot->saveAll();
ErrorCode = 0;
ClientSocket->Close();

reconnectValue = 4000;
reconnectTimer = 0;
TrayMessage(NIM_MODIFY);
}

void __fastcall TForm1::SendTimer(TObject *Sender)
{
reconnectTimer++;
if(reconnectTimer == reconnectValue)
{
reconnectValue = -1;
Connect1Click(Sender);
}

myCounter++;
if(Bot != NULL)
{
Bot->sendoBuffer(ClientSocket->Socket);
}

if(myCounter%120000 == 0) // every hour
{
Bot->saveAll();
Output->Clear();
}
// if(myCounter == 20160000) // every 7 days
if(myCounter == 2000)
{
Bot->mailDump();
myCounter = 0;
Bot->countingSince = myCounter;
Bot->saveAll();
}
}

void GuideBot::eek:nConnect(TCustomWinSocket *Socket)
{
stayConnected = true;
AnsiString command;
command = setDGLevel();
Socket->SendText(command + char(10));
Socket->SendText(getHandle() + char(10));
Socket->SendText(getPassword() + char(10));
if(theGuides.begin() == theGuides.end())
int lalala = 0;
loadAll();
if(theGuides.begin() == theGuides.end())
int lalala = 0;
countingSince = Form1->myCounter;
}

void GuideBot::loadAll()
{
int iPos, answered;
AnsiString theLine, guideName;

TStringList *strList = new TStringList; // declare the list
try // use the list in a try block
{
strList->LoadFromFile("guides.ini");
for(int i = 0; i < strList->Count; i++)
{
theLine = strList->Strings;
iPos = theLine.Pos("\'");
guideName = theLine.SubString(1, iPos-1);
theLine = theLine.SubString(iPos+1, theLine.Length()-iPos+1);
answered = theLine.SubString(1, theLine.Length()).ToInt();
theGuides.insert(guideMap::value_type(guideName, answered));
}
strList->LoadFromFile("admins.ini");
for(int i = 0; i < strList->Count; i++)
{
theLine = strList->Strings;
iPos = theLine.Pos("\'");
guideName = theLine.SubString(1, iPos-1);
theLine = theLine.SubString(iPos+1, theLine.Length()-iPos+1);
answered = theLine.SubString(1, theLine.Length()).ToInt();
theAdmins.insert(guideMap::value_type(guideName, answered));
}
strList->LoadFromFile("gheads.ini");
for(int i = 0; i < strList->Count; i++)
{
theLine = strList->Strings;
iPos = theLine.Pos("\'");
guideName = theLine.SubString(1, iPos-1);
theLine = theLine.SubString(iPos+1, theLine.Length()-iPos+1);
theGAdr.insert(adrMap::value_type(guideName, theLine));
}
strList->LoadFromFile("aheads.ini");
for(int i = 0; i < strList->Count; i++)
{
theLine = strList->Strings;
iPos = theLine.Pos("\'");
guideName = theLine.SubString(1, iPos-1);
theLine = theLine.SubString(iPos+1, theLine.Length()-iPos+1);
theAAdr.insert(adrMap::value_type(guideName, theLine));
}
strList->LoadFromFile("tdheads.ini");
for(int i = 0; i < strList->Count; i++)
theTDHeads.insert(strList->Strings);
}
__finally
{
delete strList; // destroy the list object
}

TIniFile *times;
times = new TIniFile(ExtractFilePath(Application->ExeName)
+"times.ini");
assistsAsked = times->ReadInteger("assists", "assistsAsked", 0);
guestAssists = times->ReadInteger("assists", "guestAssists", 0);
unansweredAssists = times->ReadInteger("assists", "unansweredAssists",
0);
delete times;
}

void GuideBot::saveAll()
{
AnsiString aLine;

int sec = 60*(Form1->myCounter - countingSince)/2000;
int min = 0;
int hour = 0;
int day = 0;
while(sec >= 60)
{
min = sec/60;
sec -= min*60;
}
while(min >= 60)
{
hour = min/60;
min -= hour*60;
}
while(hour >= 24)
{
day = hour/24;
hour -= day*24;
}

TIniFile *times;
times = new TIniFile(ExtractFilePath(Application->ExeName)
+"times.ini");
times->WriteInteger("guides", "sec", sec);
times->WriteInteger("guides", "min", min);
times->WriteInteger("guides", "hour", hour);
times->WriteInteger("guides", "day", day);

times->WriteInteger("assists", "assistsAsked", assistsAsked);
times->WriteInteger("assists", "guestAssists", guestAssists);
times->WriteInteger("assists", "unansweredAssists",
unansweredAssists);

delete times;

times = new TIniFile(ExtractFilePath(Application->ExeName)
+"settings.ini");
times->WriteInteger("Program", "myCounter", Form1->myCounter);
delete times;

TStringList *strList = new TStringList; // declare the list
try // use the list in a try block
{
guideMap::iterator itr;
for(itr = theGuides.begin(); itr != theGuides.end(); itr++)
{
aLine.sprintf("%s'%i", (*itr).first, (*itr).second);
strList->Add(aLine);
}
// if(strList->Count > 0)
strList->SaveToFile("guides.ini");
}
__finally
{
delete strList; // destroy the list object
}
strList = new TStringList;
try // use the list in a try block
{
guideMap::iterator itr;
for(itr = theAdmins.begin(); itr != theAdmins.end(); itr++)
{
aLine.sprintf("%s'%i", (*itr).first, (*itr).second);
strList->Add(aLine);
}
strList->SaveToFile("admins.ini");
}
__finally
{
delete strList; // destroy the list object
}
strList = new TStringList;
try // use the list in a try block
{
adrMap::iterator itr;
for(itr = theGAdr.begin(); itr != theGAdr.end(); itr++)
{
aLine.sprintf("%s'%s", (*itr).first, (*itr).second);
strList->Add(aLine);
}
// if(strList->Count > 0)
strList->SaveToFile("gheads.ini");
}
__finally
{
delete strList; // destroy the list object
}
strList = new TStringList;
try // use the list in a try block
{
adrMap::iterator itr;
for(itr = theAAdr.begin(); itr != theAAdr.end(); itr++)
{
aLine.sprintf("%s'%s", (*itr).first, (*itr).second);
strList->Add(aLine);
}
// if(strList->Count > 0)
strList->SaveToFile("aheads.ini");
}
__finally
{
delete strList; // destroy the list object
}
strList = new TStringList;
try // use the list in a try block
{
headSet::iterator itr;
for(itr = theTDHeads.begin(); itr != theTDHeads.end(); itr++)
strList->Add(*itr);
// if(strList->Count > 0)
strList->SaveToFile("tdheads.ini");
}
__finally
{
delete strList; // destroy the list object
}
}

void GuideBot::mailDump()
{
if(theGuides.begin() == theGuides.end())
{
loadAll();
return;
}
TIniFile *times;
int total = 0;
int guides = 0;
int sec;
AnsiString ending1, ending2, aLine;
guideMap::iterator itr1;
adrMap::iterator itr2;
TStringList *strList;

Form1->MailSender->PostMessageA->Body->Clear();
Form1->MailSender->PostMessageA->ToAddress->Clear();

sec = 60*(Form1->myCounter - countingSince)/2000;
int min = 0;
int hour = 0;
int day = 0;

times = new TIniFile(ExtractFilePath(Application->ExeName)
+"times.ini");
sec += times->ReadInteger("guides", "sec", 0);
min += times->ReadInteger("guides", "min", 0);
hour += times->ReadInteger("guides", "hour", 0);
day += times->ReadInteger("guides", "day", 0);
delete times;
while(sec >= 60)
{
min = sec/60;
sec -= min*60;
}
while(min >= 60)
{
hour = min/60;
min -= hour*60;
}
while(hour >= 24)
{
day = hour/24;
hour -= day*24;
}
ending1.sprintf("Counting since %i days, %i hours, %i minutes and %i
seconds.", day, hour, min, sec);
ending2.sprintf("%i assists were asked, of which %i (%2.1f%%) were
guest assists. %i assists were left unanswered (%2.1f%%)", assistsAsked,
guestAssists, ((assistsAsked == 0) ? 0.0 : ((float)guestAssists/(float)
assistsAsked)*100), unansweredAssists, ((assistsAsked == 0) ? 0.0 :
((float)unansweredAssists/(float)assistsAsked)*100));

strList = new TStringList();
try
{
for(itr1 = theGuides.begin(); itr1 != theGuides.end(); itr1++)
{
aLine.sprintf("%s answered %i assists", (*itr1).first,
(*itr1).second);
Form1->MailSender->PostMessageA->Body->Add(aLine);
strList->Add(aLine);
guides++;
total += (*itr1).second;
}
aLine.sprintf("%i Guides answered %i assists (%2.1f%% of answered
assists)", guides, total, ((assistsAsked-unansweredAssists == 0) ? 0.0 :
((float)total/(float)(assistsAsked-unansweredAssists))*100));
Form1->MailSender->PostMessageA->Body->Add(aLine);
strList->Add(aLine);
Form1->MailSender->PostMessageA->Body->Add(ending1);
strList->Add(ending1);
Form1->MailSender->PostMessageA->Body->Add(ending2);
strList->Add(ending2);
Form1->MailSender->PostMessageA->Subject = "Guide assist stats";

for(itr2 = theGAdr.begin(); itr2 != theGAdr.end(); itr2++)
Form1->MailSender->PostMessageA->ToAddress->Add((*itr2).second);

Form1->MailSender->Connect();
Form1->MailSender->SendMail();
Form1->MailSender->Disconnect();

Form1->MailSender->PostMessageA->Body->Clear();
Form1->MailSender->PostMessageA->ToAddress->Clear();

guides = 0;
total = 0;
for(itr1 = theAdmins.begin(); itr1 != theAdmins.end(); itr1++)
{
aLine.sprintf("%s answered %i assists", (*itr1).first,
(*itr1).second);
Form1->MailSender->PostMessageA->Body->Add(aLine);
strList->Add(aLine);
guides++;
total += (*itr1).second;
}
aLine.sprintf("%i Admins answered %i assists (%2.1f%% of answered
assists)", guides, total, ((assistsAsked-unansweredAssists == 0) ? 0.0 :
((float)total/(float)(assistsAsked-unansweredAssists))*100));
Form1->MailSender->PostMessageA->Body->Add(aLine);
strList->Add(aLine);
Form1->MailSender->PostMessageA->Body->Add(ending1);
strList->Add(ending1);
Form1->MailSender->PostMessageA->Body->Add(ending2);
strList->Add(ending2);
Form1->MailSender->PostMessageA->Subject = "Admin assist stats";

for(itr2 = theAAdr.begin(); itr2 != theAAdr.end(); itr2++)
Form1->MailSender->PostMessageA->ToAddress->Add((*itr2).second);

Form1->MailSender->Connect();
Form1->MailSender->SendMail();
Form1->MailSender->Disconnect();

strList->SaveToFile("dump.txt");
}
__finally
{
delete strList;
}

guideMap::iterator itr;
for(itr = theGuides.begin(); itr != theGuides.end(); itr++)
(*itr).second = 0;
theAdmins.clear();
assistsAsked = 0;
guestAssists = 0;
unansweredAssists = 0;
}
 
S

S. Han

It's a rather long code and I think it would be pain to debug it for anyone.
I think the problem lies in the fact that your containers store AnsiString
type rather than std::string. In other words you might be storing the
pointer
to the strings which become invalid (for whatever reason) when you get
disconnected from the server multiple times.
 
D

Dave Moore

zero said:
First a short discription of my program. I have a bot that connects to
an internet chess server. Whenever the bot logs on, it loads certain
information from file, and puts it in STL containers (specifically sets &
maps). When disconnecting for any reason, the containers are converted
to strings, and saved to disk, so they can be loaded again when the bot
logs back on. Periodically (triggered by a timer event), the bot mails a
log to addresses contained in two of the maps. The same timer is used to
send the output buffer to the server (such a buffer is needed because if
you send too much data at once, the server closes the connection as a
security precaution). There is also a mechanism that automatically re-
connects the bot if it is disconnected.

Now the problem. If the bot disconnects a few times, the log gets mailed
normally the first time, but the next time it should be sent, all the
containters are empty! This of course means the log can't be sent,
'cause it gets the mail addresses from two of the containers. I have no
idea how or why this happens.

I'd appreciate any ideas on how to fix this.


Here are some parts of the code:


typedef std::map<AnsiString, int, myless> guideMap;
typedef std::map<AnsiString, AnsiString, myless> adrMap;
typedef std::set<AnsiString> headSet;
[rest of code snipped]

Sorry, but that is just too much code for me to wade through right now
(maybe ever) .. however, from your description of the problem, I get
the impression that the weak link is probably in the saving/loading
interactions with the storage file and the STL containers. How well
have you tested that? Parsing input files ... even ones you wrote
yourself and (think you) understand .. is probably the most
error-prone programming operation of all. I would suggest you satisfy
yourself that the saveAll() and particularly the loadAll() members of
Guidebot behave as you expect. Right now there is precious little
error condition testing of the fstreams (well, I guess they are
fstreams .. I could not find declarations anywhere) in those methods
.... that is almost always a recipe for disaster ... it is like sending
a "Nail Me!" letter to Murphy's house.

So, I would recommend you write a smaller test-bench for your
saveAll() and loadAll() methods, and make sure they are behaving
themselves. Chances are you will find the problem yourself ... if you
are still having trouble, post a (greatly reduced) example of the
problem here ... I think you will find more people willing to give you
a hand.

Just some (hopefully helpful) friendly advice ...

Dave Moore
 
S

Siemel Naran

zero said:
Now the problem. If the bot disconnects a few times, the log gets mailed
normally the first time, but the next time it should be sent, all the
containters are empty! This of course means the log can't be sent,
'cause it gets the mail addresses from two of the containers. I have no
idea how or why this happens.

Debug it. Check to see if the containers are being written to disk
correctly, and why.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,813
Latest member
lawrwtwinkle111

Latest Threads

Top