Will using "delete" here actually delete the object? - c++

I was implementing a LinkedList using C++, and I seem to have forgotten a few things when dealing with dynamically allocated memory.
I have a node class:
class Node {
public:
Node(int d) {
data = d;
next = NULL;
}
Node(int d, Node* n) {
data = d;
next = n;
}
int data;
Node* next;
};
and in my LinkedList class, I have the following method:
void remove(int n) {
Node* current;
current = head;
Node* previous = NULL;
while ( current->data != n && current->next != NULL) {
previous = current;
current = current->next;
}
if (current->data == n) {
previous->next = current->next;
current->next = NULL;
delete current;
}
else {
std::cout << "Node not found" << std::endl;
}
}
I seem to have forgotten..When I do delete current does that delete the Node ? Like the actual object that the pointer current points to? Or does it just delete the pointer? Or does the deletion of a pointer pointing to dynamically allocated memory using delete delete both the pointer and the object? Or do I need to have defined a Node class destructor for that?

It just deletes the struct -in your case node- it points to, you can still use that pointer -make it point to another node-, in fact there's no way delete the pointer itself since it's allocated on the stack. it's automatically "deleted" when you leave the function.
p.s: no need to set current->next to null

Delete just free's the memory pointed to. This has the following implications:
You are not allowed to access the memory at this location (use after free)
The amount of memory you needed for your Node object is free, meaning your program would use less RAM.
The pointer itself points either to a non-valid location or NULL, if you follow best practise and set it to NULL manually.
The data at the memory location where your object was can be overwritten by any other task that has a valid pointer on this location. So technically the Node data still remains in memory as long as nobody else overwrites it.

delete p causes the object pointed to by p to cease to exist. This means that
1, If the object has a destructor, it is called; and
2. p becomes an invalid pointer, so that any attempt to dereference it is undefined behaviour.
Generally, the memory occupied by said object becomes available to the program again, though this is really an implementation detail.
The phrase "delete the pointer" is normally a sloppy shorthand for "delete the object pointed-to by the pointer".

Assuming that you have allocated your object using new delete on a pointer does the following:
calls the destructor of the object
request that the memory is free ( when that happens is actually implementation dependent )
At some point the memory manager will free and mark it as non-accessible by the process.
Thus it is up to you to set the pointer after calling delete to an agreed value. The best practice it to set it as nullptr for the latest compilers.

It does delete the actual structure pointed to by current. Pointers remain intact. No need for defining destructor.
The delete operator is to be applied to pointer to object. The pointer is an address of memory on heap allocated by calling new. Internally there is just table of addresses allocated by new. So the key to free such memory is just that address. In your case such address is stored in variable of type pointer to Node named current.
There are few problems in your code. The problematic one is that you have no posibility to tell whether node stored in current is actually allocated on heap. It might happen that current node is allocated on stack. E.g.
void someFunction(LinkedList &list) {
Node myLocalNode(10);
list.add(&myLocalNode);
list.remove(10); //<-- disaster happens here
}
The same applies to statically allocated global variables.
You must take care of extreme cases. Think about what happens when deleted object is the first one, pointed by variable head. By deleteing its memory you end up with dangling pointer in head, pointing to either unallocated memory or memory used by someone else.
My third objection is to writing such structure at all. I hope it is just some school excercise, because in any other cases you should (almost must) use some existing list like std::list from C++ STL.

Whenever you call delete on a pointer variable, the object to which it is pointing to gets deleted from the memory, however the 4 bytes allocated to the actual pointer variable (in your case, the current variable), the 4 bytes will be freed only when the variable will go out of scope, ie At the end of the function

Related

What happens to Node* next when deleting that Node in a linked list?

In a linked list that uses
struct Node {
T value;
Node* next;
}
For every used new operator (new Node()), there must be a delete operator.
An example of a destructor for such a list
~LinkedList(){
Node* tmp = head;
while(tmp! = nullptr){
delete tmp;
tmp = tmp->next;
}
}
My question is, what exactly gets "deleted" that allows me to use next pointer
even after delete is used? Does it only delete the value? How does that actually look in the memory?
In C++ when you delete an object on the heap nothing actually gets cleaned up, it just marks the memory as "free". This means that another call to new or malloc may overwrite that memory.
Accessing a deleted pointer is undefined behaviour because their are no guarantees on the data that resides there. I'm not very well versed in how the OS handles memory but I believe it could even be the case that your program no longer owns that page if that was the last item you deleted from that section of memory. If this happened to be the case then dereferencing that pointer will cause a segmentation fault on most desktop OS's.
If you wanted to safely move the head you should assign a temporary value to the next item while the pointer is alive, then you can delete the underlying object from memory.
When a data is deleted the pointer becomes undefined and for sure does not reach to memory it was pointing before, therefore there is no way to call tmp=tmp->next' after deletion.
The proper destructor declaration would be:
~LinkedList()
{
while (head != nullptr)
{
Node * tmp = head->next;
delete head;
head = tmp;
}
}
BTW.: Please read some good books on how to implement lists.
BTW.2: Use some standard containers like vector or list if you really need it.

Memory Leak with Pointers C++

I'm new to C++ and I found out that I have been spoiled by Java and newer programing languages like Swift. So I understand that sometimes you have to delete objects manually in C++ such as pointers. You can use the delete keyword or you can use the smart pointers. But I'm confused on whether that deletes the pointer itself, so the pointer can't be pointed again or if it deletes where the pointer is pointing.
I'm writing code that acts as a integer linked list. So I have a pointer pointing to the head and the tail of the list. When ever someone 'polls' something it should delete it from the list and then reset the head (or tail) accordingly. So I have some code that works fine for what I need it to do:
int IntegerLinkedList::pollFirst(){
if (tail == nullptr && head == nullptr) {
return 0;
} else if (head == tail) {
int ret = head->getData();
head = nullptr;
tail = nullptr;
//delete head;
//delete tail;
return ret;
} else {
IntegerNode* newHead = head->getNext();
head->setNext(nullptr);
newHead->setPrevious(nullptr);
int ret = head->getData();
//delete head;
head = newHead;
return ret;
}
}
But I never really delete the object that it was pointing at, I just remove all the pointers to it. Does that delete the object like it would in Java? Or do I have to manually delete it and how would I do that? Am I memory leaking??? Thanks so much
Also the code that updates the head is
void IntegerLinkedList::addFirst(int x){
IntegerNode* n = new IntegerNode(x);
if (head == nullptr && tail == nullptr) {
head = n;
tail = n;
} else {
head->setPrevious(n);
n->setNext(head);
head = n;
}
}
And the head was defined in the header as
IntegerNode* head;
Java has a garbage collector that essentially does what smart pointers do. That is, when the last reference to an object falls out of scope clean up the memory.
The delete keyword frees up the memory at a location the pointer points to. It doesn't actually do anything to the pointer variable itself (which is just an address).
The way to correct your code would be:
else if (head == tail) { // suppose head = 0xAD4C0080
int ret = head->getData();
delete tail; // cleans memory at 0xAD4C0080, head and tail are still 0xAD4C0080
head = nullptr; // now head = 0
tail = nullptr; // now tail = 0
return ret;
} else {
IntegerNode* newHead = head->getNext();
head->setNext(nullptr);
newHead->setPrevious(nullptr);
int ret = head->getData(); // obtain data while head still exists
delete head; // get rid of head
head = newHead; // remove stray reference to deleted memory
return ret;
}
If you attempted to use the value 0xAD4C0080 after calling delete in these examples you would get a segmentation fault.
As for smart pointers (quoting from your comment):
yes the smart pointers, but do they delete what it is pointing at or just themselves
Smart pointers delete what they are pointing to when they themselves get deconstructed (usually by falling out of scope). i.e.
void func() {
std::unique_ptr<int> pInt(new int);
} // pInt falls out of scope, std::unique_ptr<int>::~std::unique_ptr<int>() called
I'm confused on whether that deletes the pointer itself, so the
pointer can't be pointed again or if it deletes where the pointer is
pointing.
It deletes what the pointer is pointing to. The pointer must be pointing to an object that was allocated with dynamic scope (the new keyword).
I just remove all the pointers to it. Does that delete the object like
it would in Java?
Of course not.
Or do I have to manually delete it and how would I do that? Am I
memory leaking???
You have to manually delete it, using the delete keyword, and, yes, you are leaking memory unless you do that.
It is often said that it's easier to learn C++ from scratch, than to try to learn C++ if you already know Java. C++ objects work fundamentally differently than they work in Java.
And not only differently, but in ways that have no equivalent in Java, at all. There is no Java equivalent, for example, of an object instantiated in automatic scope, in C++.
The full explanation of various scopes of C++ class instances cannot be fully given in a brief answer on stackoverflow.com. You need to get a good book on C++, and start reading it.
And forget everything you know about classes from Java. C++ classes don't work that way. The longer you keep trying to draw analogies with Java, the longer it will take you to learn how to use C++ classes correctly.
Yes, some of the pain can be helped by using smart pointers, which will take care of some of the pain points. But understanding smart pointers in of themselves also requires complete understanding of C++'s class model. Smart pointers do not solve everything, and it is important to understand how C++ classes work, in order to understand what problems smart pointers do solve, and what problems they do not solve.
It depends on what the type is for head and tail. In C++, there are operators (e.g., operator=), and there are destructors. This can lead to certain interesting consequences. Take this example:
#include <memory>
int main() {
// allocate memory
int* ptr = new int;
// store in smart pointer
std::unique_ptr<int> smart_ptr(ptr);
// create another wrapped pointer
std::unique_ptr<int> smart_ptr2(new int);
// throw away location of allocated memory
ptr = nullptr;
// free memory by assigning to smart pointer
smart_ptr = nullptr;
// we can call delete safely here because ptr is null
delete ptr;
// data pointed to by smart_ptr2 will
// be deleted at end of scope
return 0;
}
Additionally, there are two operators for allocating memory, operator new and operator new[], which must be free'd using delete and delete[] respectively.
A more detailed explanation of these concepts may be beyond the scope of this site.
Am I memory leaking???
Yes, if you new something, you must delete somewhere. Assigning pointer to nullptr won't ever affect the allocated data.
But I'm confused on whether that deletes the pointer itself, so the pointer can't be pointed again or if it deletes where the pointer is pointing.
The delete keyword will delete the content at the address you send to it. It won't delete named variable, as variable on the stack are destructed at the end of the scope. Deleteting manually something with automatic storage led to undefined behaviour.
I see you are confused about std::unique_ptr No, they are not deleting themselves. Like any other variable, thier destructor are called and the variable is destructed. The thing about std::unique_ptr is that in their destructor, they delete the data they point to, with you having to delete it yourself. You should read about the RAII idom.
There's a thing about your code, these lines in particular:
head = nullptr;
tail = nullptr;
delete head;
delete tail;
This won't do a thing. You are deleting no data, as head and tail point to nothing. Since the delete keyword deletes the data pointer are pointing to, it won't delete anything.
However, take this example with std::unique_ptr:
{
std::unique_ptr<int> myPtr;
myPtr = std::make_unique<int>(); // or you can use `new int;`
myPtr = nullptr; // The old int you allocated with `std::make_unique` is deleted.
myPtr = std::make_unique<int>(); // assign a newly allocated int
}
// Here, myPtr will free his data as it leaves the scope.
If you use the new keyword, then you always need to use delete. Memory allocated using new is not managed.
Currently your program is leaking memory in the pollFirst method, because you do not free the memory that head and tail point to before re-assigning them. You can do this by calling delete head and delete tail before re-assignment.
You should look into using one of the smart pointer types, such as unique_ptr, if you want automatic management of the memory your pointers point to.
There are few things you should know about C++.
Destructor (DTOR) : Destructor is something which you define for your class. If you don't define a destructor of your own compiler does it for you.
When you call delete for a pointer the DTOR of that class is called which does the necessary cleanup. In order to test it, please put a breakpoint to the DTOR and run the code. Once the control hits DTOR, check the call stack, you will find out that last frame below the DTOR in call stack is the line where you call delete.
As far as the smart pointers are concerned, it does something similar to the garabage collector. Smart pointers have something called reference count. The moment reference count of a smart pointer goes to 0, the DTOR is called.
NOTE: It is advised to write your own DTOR if you have a data member in the class which is pointer.

What will get removed if i remove a pointer in c++

If I remove a pointer to an object, what will be removed? Only the pointer or also the object which the pointer points to?
For example:
Assume I have a class with a variable
int *root
If I do the following in a method of that class
int *current = root;
delete current;
Will root also be deleted or only the pointer current?
I think you have a misconception about what delete does: delete deletes an object pointed to by a pointer that was previously allocated with new:
int* p = new int; // Create a new int and save its address in p
delete p; // Delete the int
Note that this does not delete p itself in any way, but only the object p points to! You can still use p like a normal variable, e.g. reassign it.
When you have multiple pointers to a pointee you only need to call delete on one of them.
int* root = new int;
int* current = root;
delete current;
std::cout << *root; // undefined behavior
The behavior of delete is described in ยง5.3.5:
6 If the value of the operand of the delete-expression is not a null
pointer value, the delete-expression will invoke the destructor (if
any) for the object or the elements of the array being deleted. In the
case of an array, the elements will be destroyed in order of
decreasing address (that is, in reverse order of the completion of
their constructor; see 12.6.2).
Yes, root is deleted, but depending of the compiler, current can still contain the address of an unexisting variable. So you have to do this to avoid mistakes :
delete current;
current = 0;
int *pointer = new int;
After this statement pointer would be pointing( pointer would be containing the address ) to a block of memory enough to store integer. What internally happens is some chunk from free store would be assigned allocated status.
When you execute
delete pointer;
That memory is returned back to free store so as to fulfill future needs. But you pointer would be containing the same address. When you execute delete again , it would led to undefined behavior since that block is already returned to free store ( that means you have lost the control over that memory through this pointer )
So, to be on safe side you generally set pointer to 0 after deleting that memory.
pointer = NULL;
In implementation of operator delete there is code which check if pointer is NULL, if it is then it returns. So, it's said that there's no harm in deleting NULL pointer.
I hope I have covered every basics.

Can I reuse a declared pointer if it's deleted?

In a linked list, I have the following code
Node *tmp = head;
Node *del = head->next;
tmp->next = del->next;
delete del;
del = tmp->next;
In my code, I deleted the pointer del first, later I point it to tmp->next. Will this work?
You don't actually delete the pointer variable itself, you just mark the memory area that it points to as free to use for future allocations (after calling the destructor but that's a different topic). The pointer variable just carries an address. Even after deletion the pointer variable is fine, but it points to an area in memory that has been freed, so its contents are undefined.
When the pointer variable is then reassigned to point to another memory address, it will have nothing to do with the old, "deleted" part of memory at all.

Destructor for a doubly-linked list that points to its value

Suppose I have a doubly-linked list defined by the class
class list
{
/*...*/
private:
struct node
{
node* prev;
node* next;
int* value;
}
node* first; //NULL if none
node* last; //NULL if none
/*...*/
}
If I wanted to make a destructor for this list do I have to explicitly delete the value?
list::~list()
{
node* move = first;
while(first)
{
first = move->next;
delete move;
move = first;
}
}
Would the above work to ensure that no memory is leaked? Or do I have to do:
list::~list()
{
node* move = first;
while(first)
{
first = move->next;
delete move->value;
delete move->prev;
delete move;
move = first;
}
}
I'm confused as to how I can make sure that no memory is leaked in this case. How do I deal with the pointers in the nodes specifically? If I delete move does it automatically take care of these?
You need to pair each new with exactly one delete. That is, you probably don't want to delete prev (this node already was deleted) but you want to delete value. Well, I'd embed the value into the object and not point to it:
struct node
{
node* prev;
node* next;
int value;
};
If the value absolutely needs to be a pointer, I'd use a std::unique_ptr<int> (or, if you need to use C++ 2003, a std::auto_ptr<int>).
For each successful new expression, call delete exactly once on that object.
For each successful new[] expression, call delete[] exactly once on that object.
That means that neither of your cleanup functions are OK:
The first function forgets to delete the value, which means a memory leak.
The second function, by deleting both move and move->prev at each node in the list, risks deleting most nodes twice, which is Undefined Behavior.
To avoid the memory leak for the first function, simply store the integer directly instead of allocating it dynamically.
Whether you have to delete the memory pointer by the value member - only you can know. It is a question of memory ownership, a question of your design. If the list owns the data memory pointed by the value members, then you have to delete it in the list destructor (i.e. when the list dies, the data it owned dies with it).
If the list does not own the value memory, then you are not supposed to delete it. Again, only you can answer the question of whether your list is supposed to own the value memory. It is a matter of your intent.
Now, as for the memory occupied by node objects, it is obviously owned by the list, so it has to be carefully deallocated in the destructor. The first version of your destcructor is close to being correct (the second makes no sense at all), except that it written in a slightly obfuscated fashion. This should be sufficient
list::~list()
{
while (first)
{
node *move = first;
first = first->next;
delete move;
}
}
(Again, if you have to delete value, then delete move->value should be added to your cycle before delete move.)
P.S. Once you get this, you might want to look into various smart pointer classes, which allow you to explicitly express memory ownership relationsips, thus making them known to the compiler. When used properly, they will make memory management almost automatic.