I have problem with c++ pointer delete and re allocation. please give me a idea about this two method. I have no chance to use smart pointers.(This is not an actual code- I should replace reference type with int)
#include <iostream>
#include <queue>
using namespace std;
int main() {
queue<int*>q;
int* a= new int(5);
q.push(a);
/* 1. method */
while (!q.empty()) {
int* x = q.pop();
....do something...
delete x;/* is here deleting the firstly created int a object? */
/* or only deleting newly created allocation of *x? */
}
/* 2. method */
int* x = q.pop();
while (!q.empty()) {
....do something...
*x = q.pop();
}
/* here i'm reallocating the values for x. is here deleting firstly created int a object? */
/* is 2 method = 1 method ? */
return 0;
}
delete x;/* is here deleting the firstly created int a object? */
Yes. The new call allocated memory and returned a pointer, which you pushed onto your queue. You then (tried to) pop the value into x. You can copy pointers around as much as you want, but they are only allocated and deleted once.
/* or only deleting newly created allocation of *x? */
What? No. Whatever you were trying to ask, the answer is no. The question is troubling.
/* here i'm reallocating the values for x. is here deleting firstly created int a object? */
No, you are not "reallocating the values for x". Assuming this code compiles (which it doesn't), but assuming that it does what it's obvious you thought it should do, then the answer is no. You also do not delete the "firstly created int a object".
What happens is you leak the memory for the original value stored in a (and subsequently pushed to your queue) because you never delete it. Furthermore, the queue is empty after the first pop and you never enter the loop.
But if you did enter the loop, you have a type conflict where you are now storing the pointer you just popped into the integer-sized memory location you originally allocated in a and popped out into x. Your compiler should warn you about this.
Now let's suppose you instead say (and here I'm also showing you the correct way to access and pop from std::queue):
x = q.front();
q.pop();
Now you have still leaked the old value of x because you did not store it anywhere else and did not delete it. And you have replaced it with the next value in the queue, which you also don't delete and so you also presumably leak.
/* is 2 method = 1 method ? */
No. Method 1 is the most correct, but you still have it wrong. You meant:
while( !q.empty() )
{
int *x = q.front();
q.pop();
// do something...
delete x;
}
Related
I'm trying to add pointers to a vector in C++. As such:
Puzzle * puzzleStart = new Puzzle();
std::vector<Puzzle*> OPEN;
OPEN.push_back(puzzleStart);
The first time a pointer is pushed, there is no problem. The second time, it causes a crash. I'm guessing the issue is the size of the vector, but I don't understand why. Is there anything more to this?
Update: You are right, the problem is elsewhere, I just realized that it occurs while I free the vector of pointer. There is another issue, if the vector contains dupplicates of pointers I think.
if (OPEN.size()!=0){
for (int i = 0; i < OPEN.size(); ++i) {
delete OPEN[i]; // Calls ~object and deallocates *tmp[i]
}
OPEN.clear();
}
How do i make sure that it doesn't try to erase allready deleted pointers?
You are right, the problem is elsewhere, I just realized that it occurs while I free the vector of pointer. There is another issue, if the vector contains dupplicates of pointers I think.
if (OPEN.size()!=0){
for (int i = 0; i < OPEN.size(); ++i) {
delete OPEN[i]; // Calls ~object and deallocates *tmp[i]
}
OPEN.clear();
}
How do i make sure that it doesn't try to erase allready deleted pointers?
If the problem is duplication of pointers, you should consider a container that does not allow duplication, such as a set. E.g.:
std::set<Puzzle*> s;
Puzzle *puzz = new Puzzle();
auto insert_result = s.insert(puzz);
if(!insert_result.second)
{
std::cout << "\"puzz\" was a duplication. No insertion made.\n";
}
// More items inserted into s, and used, etc.
for(auto p : s)
delete p;
s.clear();
When you delete the pointer, set it to nullptr. Deleting a null pointer does not cause a crash.
I am implementing a Tree, every Node has Node** inside it for the sons:
class Node {
string word;
Node* father;
Node** sons;
int sonsNum;
....
}
for inserting new son I coudnt find a way instead of making new[] array of Node* and deleting the old one (I cant use list, I am restrected...). but when deleting the old Node** using delete[], even I have saved the pointers inside to another tmp array, its values will be gone! (even Node destrucor is empty! why?). so if I use shared_ptr I think it will solve it, is there a way to do that without shared_ptr?
void insertSon(Node* sn) {
sn->father=this;
Node** tmpSons = sons; //should be shared_ptr? but I dont want that
if(sons)
//delete[](sons); // after this line, tmpSons has garbage!
sons = new Node*[sonsNum+1];
for(int i=0 ; i<sonsNum ; i++) {
sons[i]=tmpSons[i];
}
sons[sonsNum]=sn;
sonsNum++;
}
edit:
sorry forgot to said I want the real values inside the nodes so I cant copy. ( the string in this code is just for the example... its another object in real..)
edit:
solution:
void insertSon(Node* sn) {
sn->father=this;
Node** tmpSons = new Node*[sonsNum];
for(int i=0 ; i<sonsNum ; i++) {
tmpSons[i]=sons[i];
}
if(sons)
delete[](sons);
sons = new Node*[sonsNum+1];
for(int i=0 ; i<sonsNum ; i++) {
sons[i]=tmpSons[i];
}
sons[sonsNum]=sn;
sonsNum++;
delete[](tmpSons);
}
Node** tmpSons = sons; //should be shared_ptr? but I dont want that
if(sons)
//delete[](sons); // after this line, tmpSons has garbage!
Yes, that's normal -- the contents of tmpSons will be invalidated since it's just pointing to the same memory as sons, and you're freeing its contents with operator delete[].
There's no need to involve reference counting to solve this kind of problem. Simply allocate a new array (without touching sons), copy the contents of sons to the new, bigger array, and then free the memory of sons and make sons point to the new block. The key is to not free the contents of sons until you're finished copying it to your new array. It's like you don't want to throw away that CD you're copying until after you copy it (your original version was sort of throwing it away before the copy was even made). Something like this:
void insertSon(Node* sn) {
sn->father = this;
// Create a new array and copy the old data.
Node** new_sons = new Node*[sonsNum+1];
for(int i=0; i<sonsNum; i++)
new_sons[i] = sons[i];
new_sons[sonsNum++] = sn;
// Delete old data.
delete[] sons;
// Point to the new data.
sons = new_sons;
}
That should hold you up until you start worrying about things like exception-safety, at which point you probably do want to avoid relying too much on these manual memory management techniques and use more RAII-conforming objects.
Visual Breakdown
Here's a visual breakdown. First we start with the sons pointer which points go a memory block containing some "sons" of a "father" (very patriarchal naming conventions for a nodal system, btw).
Then we allocate a new, slightly bigger memory block which will be pointed to by new_sons:
Node** new_sons = new Node*[sonsNum+1];
Next we copy the former son entries into the new array.
for(int i=0; i<sonsNum; i++)
new_sons[i] = sons[i];
... and add our new entry.
new_sons[sonsNum++] = sn;
Now that we have a copy, we can throw away the old data.
// Delete old data.
delete[] sons;
... last but not least, we can make sons point to the new data. new_sons will then go out of scope and the pointer will be destroyed as well (not the stuff it's pointing to, just the pointer), and we'll end up getting what we want (sons now pointing to a new array, one entry bigger, with both the old entries and the new entry we added).
// Point to the new data.
sons = new_sons;
... and you're done.
When you do
Node** tmpSons = sons;
it doesn't copy the actual memory itself only the pointer, which means that you have two pointers both pointing to the same memory.
If you do delete[] on one of the pointers, then the other pointer will become a stray pointer, as it now points to unallocated memory. Dereferencing any of the pointers will lead to undefined behavior
but when deleting the old Node** using delete[], even I have saved the pointers inside to another tmp array, its values will be gone! (even Node destrucor is empty! why?)
But you haven't saved the pointers inside to another array. You do that after deleting the Node**. After you've deleted something, accessing it's content will have undefined behaviour.
is there a way to do that without shared_ptr?
Sure, delete tmpSons after you've copied it's content.
I cant use list, I am restrected...
I recommend using a vector.
class Test {
int a ;
int b ;
public :
Test() { }
Test(int x , int y) : a(x),b(y) { }
int getA() { return a ;}
int getB() { return b ;}
};
int main () {
list <Test *> mylist;
Test *t1 = new Test(10,20);
mylist.push_back(t1);
delete t1 ; //deleting the pointer
list <Test*> ::iterator it ;
for( it = mylist.begin() ; it != mylist.end() ; ++it ) {
Test *temp = (*it) ;
cout<<"taking data from list="<<temp->getB()<<endl;
}
return 0 ;
}
I am confuse about the output of the program , after inserting pointer in the list i deleted the pointer . Ideally it should give segmentation fault but it is printing 0 .
delete t1 ; //deleting the pointer
This deletes not the pointer, but the object, pointed by this pointer.
As you push_back pointer in the std::list, only the pointer is copied, not the real object.
Two of the standard ways to deal with this are:
if you really need to store pointers in the container, delete the object when you know, that the list will not be used anymore
the most common way to avoid such problems is to have list <Test> instead of list <Test*>.
When doing
delete t1 ; //deleting the pointer
you're deleting the object that pointer points to, not the pointer itself (which is copied by value into the list).
Taking the pointer later is a perfectly valid operation
Test *temp = (*it) ;
what it is not valid is to use a pointer to deleted memory which results in undefined behavior
cout<<"taking data from list="<<temp->getB()<<endl;
That means you might get access violation or garbage values or even the old values depending on the way memory has been managed.
Calling delete t1, just calls the destructor for the object and frees the memory.
The value of the pointer doesn't change. It is just the value of a memory address.
So you can still access the memory block pointed to by t1. But the behavior is undefined.
With a debug you might get invalid data. because some debug heap implementations fill the freed memory with a byte pattern. In a release program you might get the old values and the program seams to work correct.
Consider this piece of code.
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector <int *> test;
vector <int *> v;
int *a = new int;
int *b = new int;
*a = 1;
*b = 2;
v.push_back (a);
v.push_back (b);
for (int i = 0; i < 2; ++i)
{
int n = *v[i];
test.push_back (&n);
}
cout << *test[0] << " " << *test[1] << endl;
delete a;
delete b;
return 0;
}
The problem's statement is:
"Given this code, answer the following questions:
Why does "test" vector contain only 2's?
How can we change for loop to copy properly (only code inside for loop)?"
I couldn't answer any of these questions, so a little bit of help will be appreciated.
Thanks in advance.
That code introduces dangling pointers. The body of the loop looks like this:
{
int n = *v[i];
test.push_back (&n);
}
The local variable n loses scope as soon as the loop body ends, so the pointer &n is now a dangling pointer. If it happens that test contains only 2's, that's just what randomly came out of what is undefined behavior.
If you want to "properly" copy the data over to test, you can change the for loop body to this:
{
int* n = new int;
*n = *v[i];
test.push_back (n);
}
Please take the "properly" with a grain of salt...
You push two the same pointers to n into test array. n equals the last element of your first array. Note that after control flow exited the loop, all pointers to n become invalid. So, in fact your test array contains invalid pointers, not pointers to 2s.
You should create a copy of each integer:
int* n = new int(*v[i]);
test.push_back (n);
Note also that you have memory leak here. Each int created using new should be later destroyed using delete.
The first question is a trick question: The vector contains pointers to a variable that no longer exists, and dereferencing that could cause pretty much any output. I imagine on some machines and compilers it prints all 2s however.
I can't understand what the exercise is trying to do (why does it use vectors of pointers for example) so I can't really help with how to solve the problem.
One way you could do it is by making test store by value:
First change the test vector to vector <int> test;
Then change the push_back to something like test.push_back (n); and finally the print statements to remove the now-unneeded * operators.
EDIT for comment:
First, I'm suspect of this book: It shouldn't be demonstrating undefined behavior or raw pointers to single builtin types. But you can change your loop body if you want:
for (int i = 0; i < 2; ++i)
{
int* n = new int;
*n = *v[i];
test.push_back (&n);
}
Note that both this will cause a memory leak unless you later delete those pointers, a problem that storing by value eliminates.
1) I think that the premise of the question is faulty. The loop adds two elements to test, each contains the address of the automatic variable n, the scope of which is limited to the body of the loop. It's not guaranteed that n will be allocated the same memory location in both passes through the loop, but I suppose that it's likely that most compilers will reuse the same location in both passes.
Moreover, n is out of scope at the output statement. So referencing the pointers in test to those memory locations is undefined. Again, there's a good chance that they will still contain the values assigned in the loop.
So, only if the same location gets reused for n in the second pass of the loop and that location has not been overwritten at the time the output statement is executed, will the output be "2 2". There is no guarantee of either of these premises.
2) To get the output "1 2" without changing anything outside the loop, one could change the definition of n to int& n = *v[i], which would be a single character change from the given code, though the end result is rather strange.
A simpler solution would be to eliminate the temporary n and simply test.push_back(v[i]).
My problem is q->next always prints the same address, but I assigned q = &x;. Why it is not printing different addresses?
#include <stdio.h>
class Node
{
public:
int val;
Node *next;
Node(int v,Node *p) { val=v, next=p; }
};
int main()
{
Node head(0, NULL);
Node *q = &head;
int i = 5;
while (i>0)
{
Node x(i * 10, q);
q = &x;
printf("# %d %p\n", q->val, q->next);
i--;
}
}
In the first iteration of the loop, q contains the address of head. On each subsequent iteration, q contains the address of x.
This means that on the first iteration, q->next yields the address of head and on each subsequent iteration, q->next yields the address of x. However, x is created inside the loop, on the stack. Since there is no change to the stack inbetween, the x object always appears at the same place on the stack.
So I'd expect the program to print first the address of head and then four times the address of the four x objects (which all happen to be allocated at the same position of the stack).
I think the reason is that, within the while loop, you declare x on the stack. Then after the end of the while loop has been reached, the variable gets "destroyed". In the subsequent iteration, however, x gets reserved on the stack again using the exact same (stack) memory place.
Note that you won't get a linked list with valid pointers. You need to create Node instances on the heap using 'new' operator.
EDIT:
If you don't want to allocate memory on the heap you can use the "Linked lists using arrays of nodes" approach descriped here. The drawback is, however, that you need to know the maximum number of nodes in advance.
This has to do with the way x is allocated: It is a local variable inside the main function. That means it is allocated on the stack, at a specific position. You are reusing the same piece of memory all the time. Instead, try allocating memory for new nodes (new).
Your are creating the Node on the stack - try using new.
x is a local variable in the while loop. Its lifetime is only one iteration of the loop.
You should dynamically allocate the Node objects like so :
Node* x = new Node(value, next);
so their lifetime lasts until you de-allocate the object :
delete x;
Node x is being created on the stack, each time you go round your loop it will be getting created and then destroyed again at the end of the block. And each time round the loop it will be being created in the same location.
You probably want:
Node *x = new Node( i*10, q );
q = x;
You keep setting next to q:
Node x(i * 10, q);
Your x node is allocated on the local stack, not on the heap, so as your variable gets recycled on each loop iteration it recieves the same local address. To create i = 5 uique nodes you need to allocate object on heap using new() operator. You would also to add code to destoy your allocated objects afterwards.
example:
Node * px = new Node(i*10, 1);