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.
Related
This stupid code snipped already took my 2 hours, I cannot figure out why the destructor of the first element, the one with size 7, not called? What happens to the memory allocated for new uint16_t[7]?
#include <iostream>
using namespace std;
struct Node
{
Node(uint16_t n) : p(new uint16_t[n]) {
cout<<"Constructed with size= "<<n<<", memory addr: "<<(p)<<endl;
for(uint16_t i=0; i<n; i++) p[i] = n;
}
~Node() {
cout<<"Destructor for p[0] = "<< *p <<" with memory addr: "<<p<<endl;
delete[] p;
}
uint16_t *p;
};
int main()
{
{
Node nd1(7);
{
nd1 = Node(3);
cout << "1st place holder" << endl;
}
cout << "2nd place holder" << endl;
}
return 0;
}
The output is
Constructed with size= 7, memory addr: 0x158cc20
Constructed with size= 3, memory addr: 0x158cc40
Destructor for p[0] = 3 with memory addr: 0x158cc40
1st place holder
2nd place holder
Destructor for p[0] = 0 with memory addr: 0x158cc40
*** Error in `./a.out': double free or corruption (fasttop): 0x000000000158cc40 ***
Aborted (core dumped)
I cannot figure out why the destructor of the first element, the one with size 7, not called?
It is called. In fact, it is that destructor which causes the program to crash. The behaviour of the program is undefined because the destructor deletes the same pointer value that had previously been deleted by the destructor of the temporary object. And also before that it indirects through that invalid pointer.
What happens to the memory allocated for new uint16_t[7]?
The pointer to the memory was lost when you assigned over the object. This is called a memory leak.
This code: nd1 = Node(3); does not what you expect.
It does not replace nd1 with Node(3) and kill the old nd1.
What it does is it creates a new temporary node instance Node(3) and copy the value of every members into nd1. So both the temporary and nd1 contain a pointer that points to the same address. At that point, you leaked the memory nd1 allocated at the start of the program since no pointer is refering to it but you didn't deleted it.
When the temporary dies, nd1 points to dead memory. When nd1 runs its destructor at the second }, it delete the same pointer again hence your error.
To fix this, you'll have to implement what is called the rule of five or the rule of zero.
The easiest is the rule of zero. Simply use unique_ptr and the destruction happens as expected:
struct Node
{
Node(uint16_t n) : p(std::make_unique<uint16_t[]>(n)) {
cout<<"Constructed with size= "<<n<<", memory addr: "<<(p)<<endl;
for(uint16_t i=0; i<n; i++) p[i] = n;
}
std::unique_ptr<uint16_t[]> p;
};
int main()
{
{
Node nd1(7);
{
nd1 = Node(3); // assignement destroys the old buffer
cout << "1st place holder" << endl;
}
cout << "2nd place holder" << endl;
}
return 0;
}
This question already has answers here:
C++ delete - It deletes my objects but I can still access the data?
(13 answers)
Closed 4 years ago.
I have this simple program below:
#include <iostream>
using namespace std;
class pithikos {
public:
//constructor
pithikos(int x, int y){
xPosition = x;
yPosition = y;
}
//multiplicator of x and y positions
int xmuly(){
return xPosition*yPosition;
}
private:
int xPosition;
int yPosition;
};
int main(void){
//alloccate memory for several number of pithikous
pithikos **pithik = new pithikos*[10];
for (int i = 0; i<10; i++){
pithik[i] = new pithikos(i,7);
}
cout << pithik[3]->xmuly() << endl; /*simple print statement for one of the pithiks*/
//create pithikos1
pithikos pithikos1(5,7);
cout << pithikos1.xmuly() << endl;
//delete alloccated memory
for (int i=0; i<10; i++) delete pithik[i];
delete [] pithik;
cout << pithik[4]->xmuly() << endl;
}
The class just takes two numbers and multiplies them and return the value.
But I want the oblects to born and die.
So I allocated in this example 10 objects (pithikos) and then I am testing weather it works.
when I ran the program I get this:
21
35
28
my problem is: why do I get the value 28 after I used the command?
delete [] pithik;
how can I delete the objects if not like this?
Always delete what you create with the new keyword. If you create an array of pointers using new keyword, use delete[] to delete all the pointer elements of the array.
how can I delete the objects if not like this?
This is the correct way of deleting the objects created with new keyword.
why do I get the value 28 after I used the command?
You should not deference a pointer after it is deleted. it results in an undefined behavior. You may get the old value or a nasty segmentation fault.
1-Calling delete will mark the memory area as free. It won't necessary reset its old value.
2-Accessing freed memory will surely cause you an undefined behavior so that's extremely inadvisable thing to try
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
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.
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.