C++ Builder Delete Objects of dynamic Array - c++

I want to delete old images I created in a for loop.
The first time clicking the Button the images are created. The second time or third, whatever, the old Images that were created should now be deleted (before the loop) and then directly recreated in the loop.
Because I am getting the Image properties from the database and when someone changed something in the database you should be enabled to get the newest Image properties from the database.
I tried it with delete Image[i], free() and delete[] (whole Array) but I am always getting an Access Violation Error. Here is my following code:
TImage *Image[c]= ; //c is 5
I want to delete the old Images here and then create the new in the loop below
for (int i = 0; i < c; i++)
{
str = " Test "
Image[i] = new TImage(this);
Image[i]->Parent = BoardItem ;
Image[i]->Height = 20 ;
Image[i]->Width = 20 ;
Image[i]->Position->X = d ; // The program asks you the coordinate at the begining of a new loop
Image[i]->Position->Y = e ;
Image[i]->Bitmap = Icon->Bitmap ;
Image[i]->StyleName = str ;
Image[i]->OnClick = ImageClick ;
}

#Mykola i pulled the example out of my code , so it is not that complicated to understand. in button2 i want to delete now all images that are on tabitem1
void __fastcall TForm2::Button2Click(TObject *Sender)
{
TImage *Image[5] ;
for (int i = 0; i < c; i++) {
Image[i] = new TImage(this);
Image[i]->Parent = TabItem1 ;
Image[i]->Height = 20 ;
Image[i]->Width = 20 ;
Image[i]->Position->X = 10 ;
Image[i]->Position->Y = 10 ;
Image[i]->Bitmap = Image1->Bitmap ;
Image[i]->StyleName = "Something" ;
Image[i]->OnClick = ImageClick ;
}
}
//--------------------------------------------------------------------------
void __fastcall TForm2::ImageClick(TObject *Sender)
{
TImage *Img = dynamic_cast<TImage *>(Sender);
ShowMessage(Img->StyleName);
}
//--------------------------------------------------------------------------
void __fastcall TForm2::Button1Click(TObject *Sender)
{
}

You must delete single image by simple delete operator like:
for (int i = 0; i < c; i++)
{
delete Image[i];
// NULL deleted pointer
Image[i] = NULL;
}
Access Violation also may be caused because you still use this images somewhere in your code. And why did you want delete this images? As they are pointers you may simple renew values.
To reserve values for unpredictable amount of pointers TImage* you can use:
TImage** ppImage= NULL;
than create amount of pointers you want:
ppImage = new TImage*[c];
after that you may work with those pointers like you did before.

You could go like this. In the header of the class you define the array and some methods:
int c; // Maximum (better as define?)
TImage *Image[];
bool CheckImagesLoaded();
void DeleteAllImages();
void CreateImage(int nIndex, AnsiString str);
void CreateAllImages();
Then, in the constructor you init the array:
c = 5;
for (int i = 0; i < c; i++)
{
Image[i] = NULL;
}
Now you can do the check if images were already loaded:
bool TForm1::CheckImagesLoaded()
{
return Image[0]!=NULL;
}
To delete them all:
void TForm1::DeleteAllImages()
{
for (int i = 0; i < c; i++)
{
delete Image[i];
Image[i] = NULL;
}
}
Create a a single image like this (you have to expand the parameters as you need them):
void TForm1::CreateImage(int nIndex, AnsiString str)
{
Image[nIndex] = new TImage(this);
/*Image[nIndex]->Parent = BoardItem ;
Image[nIndex]->Height = 20 ;
Image[nIndex]->Width = 20 ;
Image[nIndex]->Position->X = d ; // The programm asks you the coordinate at the begining of a new loop
Image[nIndex]->Position->Y = e ;
Image[nIndex]->Bitmap = Icon->Bitmap ;
Image[nIndex]->StyleName = str ;
Image[nIndex]->OnClick = ImageClick ;
*/
}
And in a loop you can create all images as you like:
void TForm1::CreateAllImages()
{
AnsiString str = " Test ";
for (int i = 0; i < c; i++)
{
// load data from anywhere...
CreateImage(i, str);
}
}
So, now you can operate in the Button-Event.
Delete all old Images, if existing.
Create all new Images.
void __fastcall TForm1::Button1Click(TObject *Sender)
{
// Delete old Images, if existing
if (CheckImagesLoaded())
{
DeleteAllImages();
}
// Create new Images
CreateAllImages();
}
Hope this helps...

Related

C++ memory leak, where?

I'm having a problem with the code attached below. Essentially it generates a huge memory leak but I can't see where it happens.
What the code does is receiving an array of strings, called prints, containing numbers (nodes) separated by ',' (ordered by desc number of nodes), finding other compatible prints (compatible means that the other string has no overlapping nodes 0 excluded because every print contains it) and when all nodes are covered it calculates a risk function on the basis of a weighted graph. In the end it retains the solution having the lowest risk.
The problem is that leak you see in the picture. I really can't get where it comes from.
Here's the code:
#include "Analyzer.h"
#define INFINITY 999999999
// functions prototypes
bool areFullyCompatible(int *, int, string);
bool contains(int *, int, int);
bool selectionComplete(int , int);
void extractNodes(string , int *, int &, int);
void addNodes(int *, int &, string);
Analyzer::Analyzer(Graph *graph, string *prints, int printsLen) {
this->graph = graph;
this->prints = prints;
this->printsLen = printsLen;
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
this->bestReSize = INFINITY;
this->bestRisk = INFINITY;
this-> actualSize = -1;
}
void Analyzer::getBestResult(int &size) {
for (int i = 0; i < bestReSize; i++)
cout << bestResult[i] << endl;
}
void Analyzer::analyze() {
// the number of selected paths is at most equal to the number of nodes
int maxSize = this->graph->nodesNum;
float totRisk;
int *actualNodes = new int[maxSize];
int nodesNum;
bool newCycle = true;
for (int i = 0; i < printsLen - 1; i++) {
for (int j = i + 1; j < printsLen; j++) {
// initializing the current selection
if (newCycle) {
newCycle = false;
nodesNum = 0;
extractNodes(prints[i], actualNodes, nodesNum, maxSize);
this->actualResult[0] = prints[i];
this->actualSize = 1;
}
// adding just fully compatible prints
if (areFullyCompatible(actualNodes, nodesNum, prints[j])) {
this->actualResult[actualSize] = prints[j];
actualSize++;
addNodes(actualNodes, nodesNum, prints[j]);
}
if (selectionComplete(nodesNum, maxSize)) {
// it means it's no more a possible best solution with the minimum number of paths
if (actualSize > bestReSize) {
break;
}
// calculating the risk associated to the current selection of prints
totRisk = calculateRisk();
// saving the best result
if (actualSize <= bestReSize && totRisk < bestRisk) {
bestReSize = actualSize;
bestRisk = totRisk;
for(int k=0;k<actualSize; k++)
bestResult[k] = actualResult[k];
}
}
}
newCycle = true;
}
}
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
int nodesNum = 0;
for (int i = 0; i < actualSize; i++) {
extractNodes(this->actualResult[i], nodes, nodesNum, maxSize);
// now nodes containt all the nodes from the print but 0, so I add it (it's already counted but misses)
nodes[nodesNum-1] = 0;
// at this point I use the graph to calculate the risk
for (int i = 0; i < nodesNum - 1; i++) {
float add = this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
totRisk += this->graph->nodes[nodes[i]].edges[nodes[i+1]]->risk;
//cout << "connecting " << nodes[i] << " to " << nodes[i + 1] << " with risk " << add << endl;
}
}
delete nodes;
return totRisk;
}
// -------------- HELP FUNCTIONS--------------
bool areFullyCompatible(int *nodes, int nodesNum, string print) {
char *node;
char *dup;
int tmp;
bool flag = false;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL && !flag)
{
tmp = atoi(node);
if (contains(nodes, nodesNum, tmp))
flag = true;
node = strtok(NULL, ",");
}
// flag signals whether an element in the print is already contained. If it is, there's no full compatibility
if (flag)
return false;
delete dup;
delete node;
return true;
}
// adds the new nodes to the list
void addNodes(int *nodes, int &nodesNum, string print) {
char *node;
char *dup;
int tmp;
// in this case I must add the new nodes to the list
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
if (tmp != 0) {
nodes[nodesNum] = tmp;
nodesNum++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
}
// verifies whether a node is already contained in the nodes list
bool contains(int *nodes, int nodesNum, int node) {
for (int i = 0; i < nodesNum; i++)
if (nodes[i] == node)
return true;
return false;
}
// verifies if there are no more nodes to be added to the list (0 excluded)
bool selectionComplete(int nodesNum, int maxSize) {
return nodesNum == (maxSize-1);
}
// extracts nodes from a print add adds them to the nodes list
void extractNodes(string print, int *nodes, int &nodesNum, int maxSize) {
char *node;
char *dup;
int idx = 0;
int tmp;
dup = strdup(print.c_str());
node = strtok(dup, ",");
while (node != NULL)
{
tmp = atoi(node);
// not adding 0 because every prints contains it
if (tmp != 0) {
nodes[idx] = tmp;
idx++;
}
node = strtok(NULL, ",");
}
delete dup;
delete node;
nodesNum = idx;
}
You have forgotten to delete several things and used the wrong form of delete for arrays where you have remembered, e.g.
float Analyzer::calculateRisk() {
float totRisk = 0;
int maxSize = graph->nodesNum;
int *nodes = new int[maxSize];
//...
delete [] nodes; //<------- DO THIS not delete nodes
The simplest solution is to avoid using raw pointers and use smart ones instead. Or a std::vector if you just want to store stuff somewhere to index into.
You have new without corresponding delete
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
These should be deleted somewhere using delete [] ...
You allocate actualNodes in analyze() but you don't release the memory anywhere:
int *actualNodes = new int[maxSize];
In Addition, Analyzer::bestResult and Analyzer::actualResult are allocated in the constructor of Analyzer but not deallocated anywhere.
this->actualResult = new string[graph->nodesNum];
this->bestResult = new string[graph->nodesNum];
If you must use pointers, I really suggest to use smart pointers, e.g. std::unique_ptr and/or std::shared_ptr when using C++11 or later, or a Boost equivalent when using C++03 or earlier. Otherwise, using containers, e.g. std::vector is preferred.
PS: You're code also has a lot of mismatches in terms of allocation and deallocation. If memory is allocated using alloc/calloc/strdup... it must be freed using free. If memory is allocated using operator new it must be allocated with operator delete. If memory is allocated using operator new[] it must be allocated with operator delete[]. And I guess you certainly should not delete the return value of strtok.

MFC data storage guidance

I'm writing an application which will fetch all the network adapter card info and display that on screen. For my purpose I need to store them for future use.
Currently I'm using an array of CStringArray to store the data but the size of the array is fixed.
//member of class
CStringArray m_arrAdapterData[10];
//enumeration of network card
int iAdapterCount = 0;
while(some loop condition)
{
CString cstr = _T("Some data");
m_arrAdapterData[iAdapterCount].Add(cstr);
cstr = _T("Some data");
m_arrAdapterData[iAdapterCount].Add(cstr);
iAdapterCount++;
}
Now, I'm thinking to use double dimension vector or similar. Any suggestions would be helpful.
Why not use a vector ?
It allows fast random access to any element and can handle dynamic allocation.
You can modify your code somewhat as below to work with vectors.
#include <vector>
.
.
.
//member of class
vector<CString> m_arrAdapterData;
vector<vector<CString>> infoVectors;
//populating
for (int i = 0; i < 5 ; i++)
{
for (int j = 0; j< 5 ; j++)
{
CString cstr = _T("Some data");
m_arrAdapterData.push_back(cstr);
}
infoVectors.push_back(m_arrAdapterData);
}
//retrieving
vector<vector<CString>>::iterator outerItr = infoVectors.begin();
while(outerItr != infoVectors.end())
{
vector<CString>::iterator innerItr = outerItr->begin();
while(innerItr != outerItr->end())
{
cout<<*innerItr;
innerItr++;
}
outerItr++;
}

Segmentation Fault on delete[]

I've been writing a program to simulate a paging system for an assignment. The program almost works but for some reason I'm getting a segfault when I try to delete my dynamically allocated array of frames.
Here's the algorithm code:
int main(int argc, char* argv[])
{
// Initialize page count
PageCount = 0;
// Validate input
ValidateArgs(argc, argv);
// Load programs and trace from list file
Programs = LoadPrograms();
Trace = LoadTrace();
// Load main memory
MainMemory Memory = MainMemory(Programs);
// Run the Algorithm
Run(Memory);
// Print results
Print();
// Print the output to a file
PrintOutput();
return 0;
}
void Run(MainMemory memory)
{
int page, frame;
vector<int> replaceFrame;
for (long i = 0; i < Trace.size(); i++)
{
// Get page and frame
page = Programs[Trace[i].ProgramNum].GetPage(Trace[i].Word);
frame = memory.IsInMemory(page);
if (frame != -1)
{
// Access page
memory.Frames[frame].Access(i);
}
else
{
// Find page to replace
if (Algorithm == "clock")
{
replaceFrame = memory.FindClock();
}
else if (Algorithm == "lru")
{
replaceFrame = memory.FindLRU(i);
}
else
{
replaceFrame = memory.FindOldest(i);
}
// Replace page
memory.Frames[replaceFrame[0]].Replace(page, i);
// Replace with next contiguous page for prepaging
if (HowToPage)
{
memory.Frames[replaceFrame[1]].Replace(
Programs[Trace[i].ProgramNum].GetNextPage(
Trace[i].Word), i);
}
}
}
return;
}
Program and Request are both data types loaded from files. Request is just a data struct and Program has a vector of ints as one of its members.
At the end of this function, my MainMemory object (the one that contains the dynamically allocated array) calls its destructor which is in my MainMemory struct:
struct MainMemory
{
Frame* Frames;
int Number;
// Initializes an object of the MainMemory class
MainMemory(vector<Program> thePrograms)
{
Number = MemorySize / PageSize;
Frames = new Frame[Number];
int numberProgs = thePrograms.size(), counter = 0;
// Load main memory
for (int i = 0; i < numberProgs; i++)
{
for (int j = 0; j < thePrograms[i].Pages.size(); j++)
{
int page = thePrograms[i].Pages[j];
Frames[counter] = Frame(page, 0);
if (counter + 1 < Number)
{
counter++;
}
else
{
return;
}
}
}
}
// Initializes an object of the MainMemory class with another object
// of the MainMemory class
MainMemory(const MainMemory& cpy)
{
*this = cpy;
}
// Sets one MainMemory equal to another
MainMemory& operator=(const MainMemory& rhs)
{
Number = rhs.Number;
Frames = new Frame[Number];
for (int i = 0; i < Number; i++)
{
Frames[i] = Frame(rhs.Frames[i].Number,
rhs.Frames[i].TimeStamp, rhs.Frames[i].UseCount,
rhs.Frames[i].UseBit);
}
return *this;
}
// Deletes the MainMemory object
~MainMemory()
{
delete[] Frames;
Frames = NULL;
}
};
After some testing, I know that the Frames object has a memory address coming in to the destructor. Further, the code fails at the line indicated. The Frame struct doesn't have any dynamic elements so I didn't bother creating a destructor for it and instead let C++ do that for me.
struct Frame
{
int Number;
int TimeStamp;
int UseCount;
bool UseBit;
// Initializes an empty object of the Frame class
Frame() { }
// Initializes an object of the Frame class
Frame(int number, int time)
{
Number = number;
TimeStamp = time;
UseCount = time;
UseBit = false;
}
// Initializes an object of the Frame class
Frame(int number, int time, int count, bool use)
{
Number = number;
TimeStamp = time;
UseCount = count;
UseBit = use;
}
// Simulates a replacement of one frame with a page from secondary
void Replace(int page, int time)
{
Number = page;
TimeStamp = time;
UseCount = time;
UseBit = true;
PageFaults++;
return;
}
// Simulates a memory access to the frame
void Access(int time)
{
UseCount = time;
UseBit = true;
return;
}
};
But clearly, something's not working so I'm wondering where I screwed up.
Thanks for your help!
EDIT: I rechecked my constructor to see if it was shallow-copying anything. All elements in the copied element were in different locations from the original.
EDIT: I've been asked to add a SSCCE to this post:
int main(int argc, char* argv[])
{
PageCount = 0;
Programs = LoadPrograms();
Trace = LoadTrace();
MainMemory Memory(Programs);
cout << endl << "Running algorithm" << endl;
cout << endl << "Memory is at location " << &Memory << endl;
Test(Memory);
return 0;
}
void Test(MainMemory memory)
{
cout << endl << "Memory at location " << &memory << endl;
return;
}
This is the output I get:
Running algorithm
Memory is at location 0x7fff910a4eb0
Memory at location 0x7fff910a4ec0
In destructor
Frames in 0x7fff910a4ec0
Frames deleted
Destruction finished
It's copying correctly at least. Further, after changing the copy constructor, to explicitly copy the object (thanks Joachim Pileborg), it almost finishes executing Run(). However, there's still a problem with deallocating the memory. So, I think the issue is with the Run() function itself.
I would do this as a comment but the length of my reply precludes this. I can spot a number of oddities in the program that may or may not be related to the crash you are getting.
This is bad:
MainMemory(const MainMemory& cpy)
{
*this = cpy;
}
You would be creating multiple references to pointers, alloying multiple deletions of the same memory block.
Here, you do not delete Frames before assigning a new value to it.
MainMemory& operator=(const MainMemory& rhs)
{
Number = rhs.Number;
Frames = new Frame[Number];
for (int i = 0; i < Number; i++)
{
Frames[i] = Frame(rhs.Frames[i].Number,
rhs.Frames[i].TimeStamp, rhs.Frames[i].UseCount,
rhs.Frames[i].UseBit);
}
return *this;
}
I expect that this is causing the double deletions:
MainMemory Memory = MainMemory(Programs);
is then causing your problem (combined with the first issue above). Should be:
MainMemory Memory (Programs) ;
I would also question the constructor use for the Frames class.

Store and pass array in MFC-single-document

I am doing a small project of drawing tool.
When button down, capture the start point. When mouse move, draw a line. When button up, capture the final point. I use line to draw a polygon, so I use array m_polygonx to store final point.x of a line, and m_polygony to store final point.y, uint m_count to count the numbers of final points.
Here is my code:
void CDrawToolView::OnLButtonUp(UINT nFlags, CPoint point)
{
m_startRect=FALSE;
::ClipCursor(NULL);
dc.MoveTo(m_startPoint);
dc.LineTo(m_OldPoint);
dc.MoveTo(m_startPoint);
dc.LineTo(point);
m_count++;
m_polygonx[m_count] = point.x;
m_polygony[m_count] = point.y;
}
And then I pass the array to a dialog.
In my calling function:
void CDrawToolView::OnEditProperty()
{
CPropertyDlg dlg;
dlg.origin_x = m_startPoint.x;
dlg.origin_y = m_startPoint.y;
dlg.count = m_count;
for (int i=0; i < m_count ; i++)
{
dlg.polygonx[i] = m_polygonx[i];
dlg.polygony[i] = m_polygony[i];
}
if (dlg.DoModal() == IDOK)
{
m_startPoint.x = dlg.origin_x;
m_startPoint.y = dlg.origin_y;
m_count = dlg.count;
for (int i=0; i < dlg.count ; i++)
{
m_polygonx[i] = dlg.polygonx[i];
m_polygony[i] = dlg.polygony[i];
}
}
}
But the array does not stored and passed successfully. Could some one help me?

Expand and add a new object to a array inside a function

I'm trying to expand and add a new object to a array inside a function and have that array be effected outside the function as well (the arrays pointer is sent as a parameter).
void addMedia(Media* medias[], int &nrOfMedias, string title, int publYear, string author, int nrOfPages)
{
Media** tempArray = new Media*[nrOfMedias +1];
for(int i = 0; i < nrOfMedias; i++)
{
tempArray[i] = medias[i];
}
delete [] medias;
medias = tempArray;
delete [] tempArray;
medias[nrOfMedias] = new Book(title, publYear, author, nrOfPages);
nrOfMedias++;
}
This code works great inside the function but when I get outside it the array is still empty. As i understand this it's because the pointer is changed inside the function but how can i expand the array without having it change the pointer?
(I can not change the return data type or the parameters, assignment requirements.)
Do change medias = tempArray; to *medias = tempArray;, make it compile, polish your memory management (consider, what really should be freed, what not).
Don't view medias as an array of pointers, view it as a pointer to an array. Working example (slightly simplified):
class Media
{
public:
Media () { m_strTitle = "unknown";}
string m_strTitle;
};
class Book : public Media
{
public:
Book(string strTitle) { m_strTitle = strTitle; }
};
void addMedia(Media* medias[], int &nrOfMedias)
{
Media * tempArray = new Media[nrOfMedias +1];
for(int i = 0; i < nrOfMedias; i++)
{
tempArray[i] = (*medias)[i];
}
delete [] *medias;
(*medias) = tempArray;
(*medias)[nrOfMedias] = Book("newTitle");
nrOfMedias++;
}
int main()
{
int numMedia = 10;
Media * myArray = new Media[numMedia];
addMedia(&myArray, numMedia);
for (int i = 0; i < numMedia; i++)
{
cout << i << ") " << myArray[i].m_strTitle << endl;
}
return 0;
}
You don't need delete [] tempArray; because tempArray actually points to the same memory block as medias does after medias = tempArray;
Your function will work well whithout that line but I assume that you know what you pass with Media* medias[]