I have a some kind of memory leak problem. I had it in earlier lines, but i corrected it by writing a copy assignment constructor. But the problem is on the delete newB line. When i comment out that line, there is another error popping out. Where do you think i have some memory leaks because i know it is somehow related with the memory allocation.
void BankingSystem::addBranch(const int id, const string name){
if(isBranchExisting(id)){
cout << "\n\tBranch " << id << " already exists. Please try it with another id number.";
}
else if(!isBranchExisting(id)){
Branch* tempArray = new Branch[cntBranches];
if(cntBranches != 0){
for(int i = 0; i<cntBranches; i++){
tempArray[i] = allBranches[i];
}
delete[] allBranches;
allBranches = new Branch[cntBranches+1];
for(int i = 0; i<cntBranches; i++){
allBranches[i] = tempArray[i];
}
allBranches[cntBranches] = Branch(id, name);
delete[] tempArray;
}
Branch* newB = new Branch(id,name);
allBranches[cntBranches] = *newB;
cout << "\n\tBranch " << id << " is added successfully.";
delete newB;
cntBranches++;
}
}
I can show you the Branch class too if you need it because it may be related with constructors or destructor too, but i was not successful at correcting those as this error continues to pop out.
Edit: Sorry, i thought i stated it.
It fails because initially cntBranches==0 and allBranches is uninitialised, as I assume.
Thus when first time call addBranch
allBranches[cntBranches] = *newB;
will write into some random memory location pointed by garbage in allBranches.
Thru rest of pointer manipulations are incorrect and will lead to errors as well. For example delete[] tempArray; will delete everything that was allocated previously leaving allBranches pointing to deleted objects. So I'd suggest either read more about what pointer is and how mem allocation works, or use std::vector if possible.
Related
When the below code is run, I get garbage output. I have debugged it enough to figure out the error comes when I try to access hobbies[i]->hobby. Any help would be appreciated. I have been trying to figure out what is going on for hours.
int Graph::addUserToHobby(std::string hobby, std::string id){
int key = ((int)hobby[0] + (int)hobby[1])%HASHMAP_SIZE;
int collisions = 0;
while(hobbies[key] != NULL && hobbies[key]->hobby.compare(hobby) != 0 ){
key++;
collisions++;
if(key >= HASHMAP_SIZE){
key = 0;
}
}
if(hobbies[key] == NULL){
hobbylist hob;
hob.hobby = hobby;
hob.list.push_back(findVertex(id));
hobbies[key] = &hob;
}
else{
hobbies[key]->list.push_back(findVertex(id));
}
return collisions;
}
void Graph::displayHobbies(){
for(int i=0; i<HASHMAP_SIZE; i++){
if(hobbies[i] != NULL){
cout << hobbies[i]->hobby << ": ";
for(unsigned int j=0; j<hobbies[i]->list.size()-1; j++){
cout << hobbies[i]->list[j]->name << ", ";
}
cout << hobbies[i]->list[hobbies[i]->list.size()-1]->name << endl;
}
}
}
Focus your attention in that part of the code:
if(hobbies[key] == NULL) {
hobbylist hob;
...
hobbies[key] = &hob;
}
When hob gets out of scope (at the end of that if-statement's body), hobbies[key] will reference something that doesn't exist any more.
Later on in your program, as you correctly noticed, when you do cout << hobbies[i]->hobby;, you will request for hobby on something that has gone out of scope, which invokes Undefined Behavior (UB).
Some possible solutions:
Use an std::map, instead of the array of pointers you use
now. The container will automatically take care of the memory
management for you. (Recommended)
Use smart pointers (e.g. std::unique_ptr), instead of raw pointers. Read more in
What is a smart pointer and when should I use one?
Dynamically allocate hob, so that its lifetime is extended (that
means that when that if-statement's body terminates, hob's
lifetime won't terminate). This approach requires you to be
responsible for the memory management (you have to de-allocate every
piece of memory that you dynamically allocated before (call delete
as many times as you called new)).
In this part:
if(hobbies[key] == NULL){
hobbylist hob;
/* ... */
hobbies[key] = &hob;
}
hob is allocated on the stack and deleted after the if block. So the pointer you have in hobbies[key] is dangling. You can catch these sort of errors with valgrind.
Your issue is that you are populating your hobbies value with pointers to objects allocated on the stack.
These objects will have subsequently been destroyed. Perhaps you were meaning to allocate them on the heap with new?
hobbylist* hob = new hobbylist;
...
hobbies[key] = hob
there! I am new to c++ and encountered a problem of deleting pointer to an array. There was a similar question before if you search "how to properly delete a pointer to array". The conclusion of it is that it's a good habit to keep constent in using new and delete. If you use new <data-type> [] to allocate momery, delete[] should follow.
I am not satisfied with this answer. What does computer do when delete or delete[] is excuted? So, I tried this.
#include <iostream>
using namespace std;
int main()
{
int* pvalue = NULL;
pvalue = new int[3];
cout << "address of pvalue:" << pvalue << endl;
for (int i = 0; i < 3; ++i)
{
*(pvalue+i) = i+1;
}
for (int i = 0; i < 3; ++i)
{
cout << "Value of pvalue : " << *(pvalue+i) << endl;
}
delete pvalue;
cout << "address of pvalue:" << pvalue << endl;
for (int i = 0; i < 3; i++)
{
cout << "Value of pvalue : " << *(pvalue+i) << endl;
}
return 0;
}
The output is:
address of pvalue:0x150e010
Value of pvalue : 1
Value of pvalue : 2
Value of pvalue : 3
address of pvalue:0x150e010
Value of pvalue : 0
Value of pvalue : 0
Value of pvalue : 3
Address of that pointer is not NULL as I expected, and only two values are deleted.
If I substitute delete pvalue to delete [] pvalue, I would expect that all three values of array are deleted. But, the result is the same.
Does delete pvalue tell the computer that this address is free to
use somewhere else and doesn't actually change the address that
pvalue holds?
Does delete pvalue or delete [] pvalue change the values that pointer points to?
What's the difference between delete pvalue and delete [] pvalue? It seems like that they behave the same.
Does "delete pvalue" tell the computer that this address is free to use somewhere else and doesn't actually change the address that pvalue
holds?
Yes. Exactly this.
Does "delete pvalue" or "delete [] pvalue" change the values that pointer points to?
In the very simple case you have shown, no. In general, the destructor of the pointed-to values will be called. This may or may not change the values. Finally (and this is important), there is no way for a valid C++ program to tell - once you have called delete, it is undefined behaviour to examine the values. (Undefined behaviour means anything can happen - including "what you erroneously expected".)
What's the difference between "delete pvalue" and "delete [] pvalue"? It seems like that they behave the same.
The difference is that memory allocated by new must be deleted by delete, and memory allocated by new[] must be deleted by delete[]. For some implementations there is no difference at all. For others, using delete on memory allocated by new[] will just fail to run the destructors. For others, your program may halt.
Does "delete pvalue" tell the computer that this address is free to use somewhere else and doesn't actually change the address that
pvalue holds?
Yes
Does "delete pvalue" or "delete [] pvalue" change the values that pointer points to?
It may call the destructor of the object/objects
What's the difference between "delete pvalue" and "delete [] pvalue"? It seems like that they behave the same.
One deletes one object, the other delets an array of objects.
bool StudentList::remove(const char * studentName)
{
for (int i = 0; i < MAX_SIZE; i++)
{
if (this->students[i]->isEqualTo(studentName)) // Finds a name to remove
{
cout << "Remove: "; // Displays name wished to be removed
students[i]->print();
// delete[] students[i]; - Crashes
// students[i] = NULL; - Replaces removed name with null, stops working.
// students[i]->~Student(); - Call deconstructor, Crashes.
return true;
}
}
return false;
}
I just want to remove a single element out of the array, but keeps crashing when i delete that element.
students[i] is a pointer array, and i need to remove selected elements
First quetion, if you really need to delete "Student" object. If yes, you can add some bad code like:
students[i] = nullptr;
If your students are stored not only in this array, you can make that storage responsible for their deleting. But both ways aren't very good because of using null pointers later. Learn how to use collections, for example vector. You will be able just remove the pointer from an array.
It seems that you want to delete each instance of students, if you could find the studentname.
students seems a two dimensional structure pointer to a pointer. ie; **students. But, you are deleting it in wrong way.As you first need to delete the instance of students[i], then delete the instance of students.
Also, since you are calling the destructor students[i]->~Student(); after deleting instance, it may crash again, as you have assigned student[i] = NULL. then it will be, NULL->~Student() -it will also lead crash.
You need to delete it in following way :
for (int i = 0; i < MAX_SIZE; i++)
{
if (this->students[i]->isEqualTo(studentName)) // Finds a name to remove
{
students[i]->~Student();
delete students[i];
students[i] = NULL;
}
}
delete[] students;
students = NULL;
I am trying to create custom string implementation in c++ and I have a problem with overloading operator "+". I want to append new string to existing one and when I try to allocate a new extended string, debugger allocates around 12 bytes more then it should. I have no control over allocation, he just ignores variable "length". Here is the code:
class String
{
private:
char *ptrNiz;
public:
String(const char *niz = "")
{
ptrNiz = new char[strlen(niz)+1];
strcpy_s(ptrNiz, strlen(niz)+1, niz);
cout << "stvoren niz: " << ptrNiz << endl;
}
String(const String& refString)
{
ptrNiz = new char[strlen(refString.ptrNiz) + 1];
strcpy_s(ptrNiz, strlen(refString.ptrNiz) + 1, refString.ptrNiz);
cout << "Kopiran niz: " << ptrNiz << endl;
}
~String()
{
cout << "Unisten objekt: " << ptrNiz << endl;
delete[] ptrNiz;
}
int Length() const
{
return strlen(ptrNiz);
}
int CharAt(int i) const
{
return ptrNiz[i];
}
void Ispisi()
{
cout << ptrNiz << endl;
}
operator char*()
{
return ptrNiz;
}
String operator+=(const const String& ref)
{
const int const length = ref.Length() + this->Length() + 1;
char *temp = new char[length]; // ignores length and allocates more space
for (int i = 0; i < this->Length(); i++)
{
temp[i] = ptrNiz[i];
}
for (int j = 0; j < ref.Length(); j++)
{
temp[this->Length() + j] = ref.ptrNiz[j];
}
return String(temp);
}
};
char *temp = new char[length]; // ignores length and allocates more space
All which your C++ implementation is required to do here is returning a pointer to a memory location with room for length bytes. Nothing more, nothing less. It is allowed to internally allocate more bytes, even though your code must not try to access them (or else the behaviour is undefined).
The low-level details of dynamic memory allocation is an implementation issue, not your code's concern.
A debug build is a very good example for a situation in which a C++ implementation may use extra bytes for debugging information. In fact, that's probably what is happening here. I suppose you are using Visual C++. As its documentation (CRT Debug Heap Details) says:
When you request a memory block, the debug heap manager allocates from
the base heap a slightly larger block of memory than requested and
returns a pointer to your portion of that block.
[...]
The additional memory allocated by the debug heap routines is used for
bookkeeping information, for pointers that link debug memory blocks
together, and for small buffers on either side of your data to catch
overwrites of the allocated region.
Note that there are very many other grave errors in your code. I decided to ignore them for now and just answered the exact question you asked.
You are allocating twice, once in the constructor and again in the operator+= method. You also aren't deleting the pointer in the operator function so that memory is leaking. Either use smart pointers or provide an additional constructor parameter which specifies the ownership of the incoming pointer.
In your code please add the following line in to terminate the string with NULL;
String operator+=(const const String& ref)
{
// You code goes here
temp[length - 1] = '\0';
return String(temp);
}
This will work as expected.
Hope this helps.
This is really weird. If I increase the value of asize just by one crashSystem() does what its name speaks. Second function returning an int pointer works ok with much bigger values. Those two functions just delete and allocate the same dynamic array with same size (I created it just for test purposes).
Note: I think it could have something to do with maximum stack capacity 1MB (130037 * 8 in bytes is near 1MB), but it's really strange 'cause allocating using new inside function should work the same as any other new.
Using Visual Studio 2015
#include <iostream>
void crashSystem(int * dynamicArray, int asize) {
delete[] dynamicArray;
//dynamicArray = nullptr; does not matter at all
dynamicArray = new int[asize];
std::cout << "mem allocated\n";
}
int * worksOk(int * dynamicArray, int asize) {
int * newDynamicArray = new int[asize];
delete[] dynamicArray;
std::cout << "mem allocated\n";
return newDynamicArray;
}
int main()
{
int asize = 130037; // dynamic array size
//asize = 12330037; // for testing second function that works
int * dynamicArray;
dynamicArray = new int[asize];
for (int i = 0; i < 100; i++)
{
std::cout << "iteration " << i << " ";
crashSystem(dynamicArray, asize);
//dynamicArray = worksOk(dynamicArray, asize);
}
std::cout << "\n";
system("PAUSE");
}
Note 2: Crashing app this way in Release mode tends to block executable by creating non existent process (checked with Process Hacker 2)
The problem is that you're passing pointer by value, so it still points to the new int[asize]; allocated in main(), on which you then call multiple delete [].
It becomes a dangling pointer after the first delete [] call.
Even assigning nullptr won't help you if the pointer is not being passed by reference.
worksOk works, because you're returning the pointer pointing to the newly allocated space and assigning it, so it's valid every time.
Just change the signature so it uses reference:
void crashSystem(int *&dynamicArray, int asize)
and it should work fine.