typedef struct { int a; int b; int c; int d } A;
queue <A> q;
A* ptr;
q.push({1,2,3,4});
ptr = &(q.front());
q.pop();
ptr->a;
...
I figured out that this code might cause segmentation fault. because ptr ends up pointing to the popped element.
but I don't know the exact reason why this happens. I just presume that pop operation interally deallocates the memory for the popped. Is my presumption right? or any other reasons?
In c++ documents(https://cplusplus.com/reference/queue/queue/pop/)
std::queue::pop is described as
Removes the next element in the queue, effectively reducing its size by one.
The element removed is the "oldest" element in the queue whose value can be retrieved by calling member queue::front.
This calls the removed element's destructor.
This member function effectively calls the member function pop_front of the underlying container object.
so pointing to the popped element is invalid.
Related
In the code below I call the ~destructor() explicitly. However the object is still accessible. How can I delete it(make it disappear)?
class Queue {
public:
node* top = NULL;//points to the top of the queue
//methods:
void enqueue(int data);//adds a node to the queue
void dequeue();
//printing
void print();
//destructor
~Queue();
};
And the destructor:
Queue::~Queue() {
//The destructor deletes all items from HEAP
//Then sets the top to 0
while (top != NULL)
this->dequeue();//dequeue until there are NO more items
top = 0;
}
In Source.cpp:
Queue q;
q.enqueue(1);
q.enqueue(2);
q.enqueue(3);
q.enqueue(4);
q.dequeue();
q.dequeue();
q.print();
q.~Queue();
q.print();//Here I need to have an ERROR!
q.enqueue(7);//Here I need to have an ERROR!
q.print();//Here I need to have an ERROR!
The output is:
4 3 7
I expect an error:
identifier "q" is undefined
Taking //Here I need to have an ERROR! literally, here is how you would do that:
{
Queue q;
q.enqueue(1);
q.enqueue(2);
q.dequeue();
q.print();
}
q.print(); // THIS WILL PRODUCE AN ERROR
You seem to have a misunderstanding on lifetime of stack allocated objects. Stack objects are automatically destroyed when they go out of scope. In the example the scope of q ends with }.
Calling the destructor yourself is almost always wrong (I encountered exactly one single case where it was ok to call the destructor explicitly). Why? Consider this:
{
Queue q;
q.~Queue(); // DONT DO THIS !
}
You called the destructor but when it goes out of scope it gets destroyed again and you will get nasty runtime errors.
What you do in your code:
Queue q;
q.~Queue();
q.print();
is undefined behaviour!
Also note that calling the destructor is not all that happens when an object is deleted. When an stack allocated object is deleted, first its destructor is called and then the allocated memory is freed. Usually you do not want to interfer with this process and luckily you rarely have to.
How can I delete it(make it disappear)?
You cannot make it "disappear". When an object is destroyed the bits and bytes in memory are not erased. That would be awfully inefficient. Actually I think C's free has a much better and less confusing name. Memory is freed to be used later, it is not wiped out such that it would be impossible to read what was there before.
For further reading I refer you to this exahaustive answer to a slightly different but related question: Can a local variable's memory be accessed outside its scope?
Also, I suggest you to read about RAII which relies on destructors being called automatically.
TL;DR: If you want to clear the Queue then write:
q.clear();
q.print(); // prints an empty queue!
Don't ever call the destructor of a stack allocated object! It will be called automatically.
I am new to C++ and I am trying to initialize a vector of struct as code below.
struct Node{
int x;
Node *p;
int rank;
Node(int x) {
this->p = this;
this->x = x;
this->rank = 0;
}
};
int main() {
vector<Node> disjointSets;
for (int i = 0; i < 50; i++) {
Node a(i);
disjointSets.push_back(a);
}
}
In main, I try to create a Node a each time and push it into vector. But I later find there is an issue that a is always created at the exact same memory location. Therefore, the p, which is supposed to point to each Node itself will point to the last element after the loop. May someone explain why Node a is always created at same memory address and how to solve the issue?
You have undefined behavior, because you haven't defined a custom copy constructor for your Node class.
disjointSet.push_back(a); makes a copy of a. This is using the default copy constructor, which simply does an element-wise copy of all the member variables. So in the copy, p points to the address of the original Node, not itself. But that Node is destroyed when the loop iteration ends, so the pointer is no longer valid. It's implementation-dependent, but pretty common that the loop happens to use the same stack memory for a each time through the loop, so p in all the elements points to that same address, which is no longer a valid Node.
You need to define a copy constructor that sets p to the address of the copy:
Node(const Node &oldnode) {
p = this;
x = oldnode.x;
rank = oldnode.rank;
}
and a copy assignment operator:
Node& operator=(const Node &oldnode) {
if (&oldnode != this) {
x = oldnode.x;
rank = oldnode.rank;
}
return *this;
}
Your node's are created on the stack. And address which is assigned inside the constructor points to the stack. If you want the Nodes a constant address which doesn't change while they are moved/copied into the container you need to heap allocate them and use a vector of Node pointers. E.g. a vector<std::unique_ptr<Node>>.
You are not using heap memory. Storing the address of a local variable and trying to access it elsewhere is UB. If I'm correct, The answer for "why" the same memory space is taken for each iteration of the loop is implementation defined and in this case, it is reusing the same stack space.
I am trying to learn linked list using c++. Here is my code:
#include<bits/stdc++.h>
using namespace std;
struct node
{
int data;
node *next;
};
void show(node *head)
{
node *n;
n=head;
while(n)
{
cout<<n->data<<' ';
n=n->next;
}
cout<<endl;
}
void insert(node *list,int x)
{
list->data=x;
node *t=new node;
list->next=t;
list=t;
}
int main()
{
node *head,*t,*list=new node;
head=list;
for(int i=0;i<10;i++)
{
insert(list,i+1);
}
show(head);
}
I have pointed head to the memory list is pointing to at beginning, but after insert the call of insert function, head points to the memory that list is pointing to, but was it suppose to happen. Isn't head suppose to remain unchanged?
insert() when called repeatedly on the same list makes list->next point to a new node.
That new node is not initialised, so dereferencing its next pointer (as occurs in show()) gives undefined behaviour. As soon as code has undefined behaviour, all bets are off - anything can happen.
The net effect is that, because of how insert() behaves, show() will exhibit undefined behaviour.
Since list is passed by value, assigning to it in insert() has no effect. That assignment is not visible to main().
The previous node pointed to by list->next is also lost (not released, no longer accessible).
main() also leaves list uninitialised, so using its members (in insert() or show()) causes undefined behaviour, even if problems above are fixed.
There are two problems with the insert() function.
1) The wrong node's data is set. Instead of setting the new node's data to the value being inserted, the code sets the existing head node's data to the new value. The new node's value remains uninitialized.
2) The list parameter is passed by value to insert(). Which means that:
list=t;
accomplishes absolutely nothing. Because list is passed by value, this sets the insert() function's list to the new list head. Unfortunately, when insert() returns, the new list head gets discarded, and the original list in main() remains unchanged.
Either list must be passed to insert() by reference, or insert() should explicitly return the new list.
Additionally:
main() allocates the initial head node, and leaves it completely uninitialized. This link-list will always have one extra node whose data is never initialized. This is probably not what was intended. The correct approach is to set the empty list's head pointer to NULL, an empty list, and the first insert() should then correctly instantiate the first node in the link list.
There's one other thing that's wrong with the existing code that creates the extra, uninitialized node, that makes it clearly a bug: the extra node's next pointer is also not initialized. Attempting to walk the resulting link list will result in undefined behavior, and a likely crash.
I have been pondering an issue today and it's difficult to find the answer on google.
I'm trying to understand the STL container behaviour when dealing with pointers to both objects allocated on the heap, and on the stack.
So, start with objects, no pointers ... imagine I have ...
std::vector<int> myVec;
while(true)
{
int myInt = 5;
myVec.push_back(myInt);
myVec.pop_back();
}
My understanding is that the pop_back() method will ensure the integers contained in the vector are deleted, not just removed from the container. So if this ran and did a billion iterations, I should not expect to leak memory. Everything I insert, will be deleted. A memory check shows this behaviour.
Now consider I use a vector of pointers (to objects on the heap) ...
std::vector<int*> myVec;
while(true)
{
int * myIntP = new int(5);
myVec.push_back(myIntP);
myVec.pop_back();
}
In this case, only the pointer itself ought to be removed each time pop_back() is called, and the underlying object remains un-deleted, causing a memory leak. So after a billion iterations I have quite some significant memory being used, even though I have no entries in my vector.
Now what if I have a vector of pointers (to objects on the stack) ...
std::vector<int*> myVec;
while(true)
{
int myInt = 5;
int * myIntP = &myInt;
myVec.push_back(myIntP);
myVec.pop_back();
}
Here the pointers point to stack objects. Is their memory freed in the call to pop_back(), or not? A memory check showed me that this behaviour was no memory leaked. The small amount of memory used, indicated that this behaved like objects on the stack. However this was not expected to me, because if the pointer had been passed into me from another function, to a stack variable i.e.
void myFunc(int * myIntP)
{
std::vector<int*> myVec;
myVec.push_back(myIntP);
myVec.pop_back();
}
int main()
{
int myInt = 5;
int * myIntP = &myInt;
myFunc(myIntP);
std::cout << (*myIntP) << std::endl;
return 0;
}
Then allowing the vector to free this memory, would render my myIntP pointing to removed data. So surely this can't be correct?
Could anyone help explain?
Also is there a name for "a pointer pointing to a variable on the stack" i.e. not initialised with "new"?
Thanks
Joey
while(true)
{
int myInt = 5;
int * myIntP = &myInt;
myVec.push_back(myIntP);
myVec.pop_back();
}
You only actually have one int here, myInt with a value of 5. The loop will re-use the same one. You push a pointer to that one int into the vector and then remove it. Nothing else is happening. There isn't a memory leak because you are not allocating new ints.
STD containers do nothing different for pointers than they would for a 32/64 bit interger. As far as they care, a pointer is just another number. So, if you insert a pointer into a container, it is your responsibility to delete it.
If you make a pointer to a variable on the stack, the variable will be destructed when it goes out of scope, regardless of the pointer. And destructing the pointer (as long as you don't call delete on it) will have no effect on the variable.
So if you stop using your pointer before, no problem, if you store it longer, problem...
And if you plan on using pointers on dynamically allocated variable, you should look into smart pointers.
Here the pointers point to stack objects. Is their memory freed in the call to pop_back(), or not?
No, they are not. They are freed when they go out of scope, which happens at the }. After the }, the memory is no longer used for this variable (the stack-frame popped off) and will be reused! So if you didn't pop-off the pointer right after pushing it, your vector would contain a dangling pointer when the variable goes out of scope.
So, let's go through each of your examples:
std::vector<int> myVec;
while(true)
{
int myInt = 5;
myVec.push_back(myInt);
myVec.pop_back();
}
The push_back() method makes a copy of the argument and stores the copy internally. So, if you were storing an stack-allocated object instead of a primitive, a copy constructor would have been called. The pop_back() method does not assume anything either. It removes the copy of the item you stored (whether it was a value or a pointer) and removes it from its internal storage. If the copy stored was a stack-allocated object, the class' destructor will be called when the container manages its internal memory because the copy item will no longer be in scope.
Your second example:
std::vector<int*> myVec;
while(true)
{
int * myIntP = new int(5);
myVec.push_back(myIntP);
myVec.pop_back();
}
As you stated, the integer is allocated on the heap. Calling push_back() still stores the argument. In this case, you are not storing the value of the integer "5", the value of the pointer, an address of a memory location that contains the value of "5". Since you allocated the memory that stores the "5", you are responsible for getting that pointer and deallocate the memory. The pop_back() method does not delete the pointer for you nor returns you a copy of the pointer.
Your third example has subtle differences:
std::vector<int*> myVec;
while(true)
{
int myInt = 5;
int * myIntP = &myInt;
myVec.push_back(myIntP);
myVec.pop_back();
}
In this case, you are not allocating any memory on the heap. You assigning the address of myInt, which is a stack-allocated value, to a pointer. Stack memory lives through out the life of a process and does not deallocate on its own. However, once you leave the current scope (the while loop), the memory reused by something else. The memory is still there, but it may no longer have the value you expect.
Your last example:
void myFunc(int * myIntP)
{
std::vector<int*> myVec;
myVec.push_back(myIntP);
myVec.pop_back();
}
int main()
{
int myInt = 5;
int * myIntP = &myInt;
myFunc(myIntP);
std::cout << (*myIntP) << std::endl;
return 0;
}
You were expected the memory for myInt to be dealloated after making myFunc() was called. However, container methods do not modify the supplied values. They copy them. When myFunc() pushed the myIntP pointer, it is pushing the pointer, the address of what myIntP points to, not the value in memory of that address. You would have to dereference the pointer, using call:
myVec.push_back(*myIntP);
Note that even if you did this, containers copy the value. So, myInt is still unaffected.
You are confusing and conflating "destruction" and "deletion" -- they are NOT the same thing, but are two different concepts in C++.
Deletion can only happen with pointers -- if you try to delete a non-pointer, you'll get a compile-time error. Deletion first destroys the pointed at object and then returns the memory for it to the heap.
Destruction on the other hand can happen with anything, but is mostly only of interest with classes, where it calls the destructor. With any type that has no destructor (such as int or any raw pointer type), destruction does nothing. While you CAN destroy an object manually, you pretty much never do -- it happens automatically for you when something else happens. For example, when a local variable goes out of scope, it is destroyed.
So in your code above, what happens? Well you have a local std::vector which is destroyed when it goes out of scope. Its destructor will delete anything it allocated internally, and destroy all the elements of the vector. It will NOT however, delete any elements of the vector. When you have vector<int>, that's all there is, since nothing else was allocated, but when you have a vector<int *>, if those pointers were allocated, they'll leak. If they weren't allocated (if they point at locals), there's nothing to leak.
I think you need to learn deep the scope variable validity
exemple :
{
int myVar;//Construct myVar on the stack
}//At this point, myVar is deleted with the stack
in your last exemple, you declare myInt at the start of main and don't do anything on value in myFunc.
It's normal to don't lose myInt data. it will be erase after the return 0;
vector< int > vect;
int *int_ptr = new int(10);
vect.push_back( *int_ptr );
I under stand that every "new" needs to be followed by a "delete" at some point but does the clear() method clean this memory?
What about this method of doing the same thing:
vector< int > vect;
int int_var = 10;
vect.push_back( int_var );
From what I understand, clear() calls the variables destructors, but both vect.push_back() methods in this example push an object on the vector, not a pointer. so does the first example using an int pointer need something other than clear() to clean up memory?
The first method leaks because the vector never takes ownership of the allocated pointer. In fact, it doesn't contain a pointer at all, only a copy of the value.
The second method does not leak, as no memory is dynamically allocated (except internally in the vector -- it will handle that memory itself).
When you push_back on a vector, you add a copy of the data to the vector. Therefore, in both cases, the original data still needs to be freed. In the first case, you need to delete it; in the second, it will be "freed" by the stack pointer as it goes out of scope.
Vectors make copies on push_back. Since a pointer is 'just another variable' (but one that happens to point to memory), when you push_back an integer pointer that has been previously allocated, you copy the pointer's value into the vector, causing a potential dangling pointer, since there will be two pointers pointing at the same spot in memory.
In your first example, you would need to delete the memory manually. One strategy I've used in the past for meddling with graph classes is to have something like this (vast amounts of stuff redacted due to being at work and typing quickly):
class graph //quick-format
{
vector<node*> nodes;
add_node(node n)
{
node *temp = new node;
*temp = n;
nodes.push_back(temp)
}
~graph()
{
for(int i = 0; i < nodes.size(); i++)
delete nodes[i];
}
};
As a caveat, graph's copy semantics will have to be examined. As it stands, it will result in deleting previously-free'd memory. The advantage is that you can always have the same set of nodes hanging around. Caveat Emptor, like any direct memory usage..
However, if you simply push a non-pointer variable, there is no possibility of memory leaking from your end. Possibly the vector will leak, but... that is practically impossible at this point in the maturity of the tools.