I have the following code, and for the life of me, I cannot understand why there would be an Access Violation exception? I even deleted all the OBJs, TDS etc files and put it into a new project, still the Access Violation occurs.
Essentially, this code displays a TListView in a TFrame and is to show the various current times around the world for different time zones.
Note: The code is in C++ Builder 6.
Can someone help?
BLOODY-HELL-UPDATE: Solved. I should not add items to TListView in the TFrame constructor. DUMB DUMB DUMB.
MAJOR UPDATE: It seems that when the UpdateTimes() is called via the timer, the "li->Deleting" property is TRUE. When called outside the timer, it is FALSE. Now why would "li->Deleting" be set to 'true' because it is called from the timer? If i do:
if(li->Deleting == false)
{
li->Caption = "abcd";
}
It doesnt enter the if(), when UpdateTimes() is called from the timer...... argggggh!!!
UPDATE: It seems like if I call UpdateTimes() outside of the TTimer, it works fine. But when called from the timer, it throws the Access Violation. What gives?
Header File:
#ifndef CurrentTimes_FrameH
#define CurrentTimes_FrameH
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <ExtCtrls.hpp>
#include <ComCtrls.hpp>
#include <list>
using namespace std;
//---------------------------------------------------------------------------
struct LOCATIONTIMEINFORMATION
{
AnsiString TimeZoneName;
AnsiString PlaceName;
int UtcOffsetMinutes;
TListItem* ListItem;
};
//---------------------------------------------------------------------------
class TCurrentTimesFrame : public TFrame
{
__published: // IDE-managed Components
TTimer *Timer;
TListView *ListView;
void __fastcall TimerTimer(TObject *Sender);
private: // User declarations
public: // User declarations
__fastcall TCurrentTimesFrame(TComponent* Owner);
//---------------------------------------------------------------------------
//User Code
//---------------------------------------------------------------------------
private:
list<LOCATIONTIMEINFORMATION> FTimeInformation;
typedef list<LOCATIONTIMEINFORMATION>::iterator LocationTimeInformationItr;
public:
void AddTimeInformation(LOCATIONTIMEINFORMATION lti);
void UpdateTimes();
};
//---------------------------------------------------------------------------
#endif
CPP File:
#include <vcl.h>
#pragma hdrstop
#include "CurrentTimes_Frame.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
//---------------------------------------------------------------------------
__fastcall TCurrentTimesFrame::TCurrentTimesFrame(TComponent* Owner): TFrame(Owner)
{
Timer->Enabled = false;
<strike>{
LOCATIONTIMEINFORMATION lti;
lti.TimeZoneName = "UTC";
lti.PlaceName = "Near Greenwich, England";
lti.UtcOffsetMinutes = 0;
AddTimeInformation(lti);
}</strike>
//UPADTED: Don't add TListItem from constructor
}
//---------------------------------------------------------------------------
void TCurrentTimesFrame::AddTimeInformation(LOCATIONTIMEINFORMATION lti)
{
TListItem* li = ListView->Items->Add();
li->Caption = lti.TimeZoneName;
li->SubItems->Add(lti.PlaceName);
li->SubItems->Add(lti.UtcOffsetMinutes);
li->SubItems->Add("<time will come here>");
lti.ListItem = li;
ShowMessage(AnsiString(lti.ListItem->ClassName())); //Correctly shows "TListItem"
FTimeInformation.push_back(lti);
{
LOCATIONTIMEINFORMATION temp = FTimeInformation.front();
ShowMessage(AnsiString(temp.ListItem->ClassName())); //Correctly shows "TListItem"
}
Timer->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TCurrentTimesFrame::TimerTimer(TObject *Sender)
{
UpdateTimes();
}
//---------------------------------------------------------------------------
void TCurrentTimesFrame::UpdateTimes()
{
Timer->Enabled = false;
TListItem* li;
for(LocationTimeInformationItr itr=FTimeInformation.begin();itr!=FTimeInformation.end();itr++)
{
li = itr->ListItem;
ShowMessage(AnsiString(li->ClassName())); //Access Violation:
/*
ShowMessage() above shows:
---------------------------
Debugger Exception Notification
---------------------------
Project XX.exe raised exception class EAccessViolation with message 'Access violation at address 4000567D in module 'rtl60.bpl'. Read of address 00000000'. Process stopped. Use Step or Run to continue.
---------------------------
OK Help
---------------------------
*/
}
Timer->Enabled = true;
}
//---------------------------------------------------------------------------
UPDATE A sample code demo'ing that list takes items as copy, not reference. (As far as I can see, please correct me if im making some mistake in the code below)
@Craig Young:
I'm confused... I thought structs would be added to the list as a copy not as a reference? Please take a look at the code below, it seems that a copy is being made? Or am I missing something rudimentary? Or a coding mistake below??
void PopulateData()
{
AnsiString DebugText;
list<LOCATIONTIMEINFORMATION> Data;
LOCATIONTIMEINFORMATION OnStack;
//Prints "junk"
DebugText.sprintf("%s,%s,%d,%d",OnStack.TimeZoneName,OnStack.PlaceName,OnStack.UtcOffsetMinutes,(int)OnStack.ListItem);
OnStack.TimeZoneName = "UTC";
OnStack.PlaceName = "Near Greenwich, England";
OnStack.UtcOffsetMinutes = 10;
OnStack.ListItem = (TListItem*)20;
//OnStack:
DebugText.sprintf("%s,%s,%d,%d",OnStack.TimeZoneName,OnStack.PlaceName,OnStack.UtcOffsetMinutes,(int)OnStack.ListItem);
//Add data to list
Data.push_back(OnStack);
//Get struct from list
LOCATIONTIMEINFORMATION InList = Data.front();
//OnStack:
DebugText.sprintf("%s,%s,%d,%d",OnStack.TimeZoneName,OnStack.PlaceName,OnStack.UtcOffsetMinutes,(int)OnStack.ListItem);
//InList:
DebugText.sprintf("%s,%s,%d,%d",InList.TimeZoneName,InList.PlaceName,InList.UtcOffsetMinutes,(int)InList.ListItem);
//Change OnStack
OnStack.TimeZoneName = "NONE";
OnStack.PlaceName = "USA";
OnStack.UtcOffsetMinutes = 50;
OnStack.ListItem = (TListItem*)90;
//OnStack:
DebugText.sprintf("%s,%s,%d,%d",OnStack.TimeZoneName,OnStack.PlaceName,OnStack.UtcOffsetMinutes,(int)OnStack.ListItem);
//InList:
DebugText.sprintf("%s,%s,%d,%d",InList.TimeZoneName,InList.PlaceName,InList.UtcOffsetMinutes,(int)InList.ListItem);
//Change InList:
InList.TimeZoneName = "SOME";
InList.PlaceName = "BRAZIL";
InList.UtcOffsetMinutes = 66;
InList.ListItem = (TListItem*)88;
//OnStack:
DebugText.sprintf("%s,%s,%d,%d",OnStack.TimeZoneName,OnStack.PlaceName,OnStack.UtcOffsetMinutes,(int)OnStack.ListItem);
//InList:
DebugText.sprintf("%s,%s,%d,%d",InList.TimeZoneName,InList.PlaceName,InList.UtcOffsetMinutes,(int)InList.ListItem);
}