Why no "delete" after "new" in linked list insert node - c++

I have been trying to understand memory allocation in C++ by reading some texts and looking stuff up. I have seen often that one should always call "delete" after "new". However, I also see code like this:
void LinkedList::add(int data){
Node* node = new Node();
node->data = data;
node->next = this->head;
this->head = node;
this->length++;
}
In structures like linked lists or stacks.
I have seen some great explanations on SO like:
Why should C++ programmers minimize use of 'new'?
When to use "new" and when not to, in C++?
However I am still confused why one would not call "delete" here for a new Node.
Edit: Let me clarify my question. I understand why not to immediately call delete in the same method. However, in the same code I do not see a matching delete statement for add. I assume that everything is deleted once the program ends, but I am confused that there is no apparent matching delete statement (ie: count all the news in the code, count all the deletes in the code, they do not match).
Edit: Here is the source that I am looking at: https://www.geeksforgeeks.org/linked-list-set-2-inserting-a-node/
The code for their linked list:
// A complete working C++ program to demonstrate
// all insertion methods on Linked List
#include <bits/stdc++.h>
using namespace std;
// A linked list node
class Node
{
public:
int data;
Node *next;
};
/* Given a reference (pointer to pointer)
to the head of a list and an int, inserts
a new node on the front of the list. */
void push(Node** head_ref, int new_data)
{
/* 1. allocate node */
Node* new_node = new Node();
/* 2. put in the data */
new_node->data = new_data;
/* 3. Make next of new node as head */
new_node->next = (*head_ref);
/* 4. move the head to point to the new node */
(*head_ref) = new_node;
}
/* Given a node prev_node, insert a new node after the given
prev_node */
void insertAfter(Node* prev_node, int new_data)
{
/*1. check if the given prev_node is NULL */
if (prev_node == NULL)
{
cout<<"the given previous node cannot be NULL";
return;
}
/* 2. allocate new node */
Node* new_node = new Node();
/* 3. put in the data */
new_node->data = new_data;
/* 4. Make next of new node as next of prev_node */
new_node->next = prev_node->next;
/* 5. move the next of prev_node as new_node */
prev_node->next = new_node;
}
/* Given a reference (pointer to pointer) to the head
of a list and an int, appends a new node at the end */
void append(Node** head_ref, int new_data)
{
/* 1. allocate node */
Node* new_node = new Node();
Node *last = *head_ref; /* used in step 5*/
/* 2. put in the data */
new_node->data = new_data;
/* 3. This new node is going to be
the last node, so make next of
it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty,
then make the new node as head */
if (*head_ref == NULL)
{
*head_ref = new_node;
return;
}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
return;
}
// This function prints contents of
// linked list starting from head
void printList(Node *node)
{
while (node != NULL)
{
cout<<" "<<node->data;
node = node->next;
}
}
/* Driver code*/
int main()
{
/* Start with the empty list */
Node* head = NULL;
// Insert 6. So linked list becomes 6->NULL
append(&head, 6);
// Insert 7 at the beginning.
// So linked list becomes 7->6->NULL
push(&head, 7);
// Insert 1 at the beginning.
// So linked list becomes 1->7->6->NULL
push(&head, 1);
// Insert 4 at the end. So
// linked list becomes 1->7->6->4->NULL
append(&head, 4);
// Insert 8, after 7. So linked
// list becomes 1->7->8->6->4->NULL
insertAfter(head->next, 8);
cout<<"Created Linked list is: ";
printList(head);
return 0;
}
// This code is contributed by rathbhupendra

The code you cited should delete the nodes at some point. Indeed, that code shows off tons of bad C++ practices. It doesn't delete the nodes because it's bad code.
Oh and BTW: ignore anything on the site you linked to. If there is something useful on that site, it's only by accident.

Generally new does a couple of things. It allocates memory for an object, on the heap (where dynamic memory resides), and initialises an object at the address.
When you have variables in your function like this:
void example(){
int a;
char b;
}
They reside on the stack, and when the function returns, those variables no longer exist. With new you can get memory outside the stack (on the heap). The good thing is that this persists throughout function calls. The bad thing that it persists across function calls. It's good because sometimes array lengths are not known and therefore they can not be allocated on the stack, or you need a large buffer which would not fit on the stack. It's bad because if you forget about it, then it won't go away. It will just sit there taking up memory. delete, basically destructs the object at the address, and then returns the memory to the OS. That's why people say that delete should be called after new.
Luckily in modern c++ you (generally) don't need to use raw pointers and not need to worry about this. std::shared_ptr<T> created by std::make_shared<T,Args...>, and std::unique_ptr<T> created by std::make_unique<T,Args...>. These are wrappers for pointers. std::shared_ptr<T> is just T*, but when everybody loses the pointer to the object, the memory is returned. std::unique_ptr<T> is the same, but only one reference exists.
A std::unique_ptr<T> LinkedList from cppreference:
#include <memory>
struct List {
struct Node {
int data;
std::unique_ptr<Node> next;
Node(int data) : data{data}, next{nullptr} {}
};
List() : head{nullptr} {};
// N.B. iterative destructor to avoid stack overflow on long lists
~List() { while(head) head = std::move(head->next); }
// copy/move and other APIs skipped for simplicity
void push(int data) {
auto temp = std::make_unique<Node>(data);
if(head) temp->next = std::move(head);
head = std::move(temp);
}
private:
std::unique_ptr<Node> head;
};
As to an other reason the use of new should be minimised: Apart from the above issue of potential memory leak, is that it is very expensive (std::make_shared/std::make_unique still has this issue though), as the program needs to ask the kernel to grant it some memory, meaning an expensive system call must be made.

Related

Passing a linked list without memory leak in C++

In many occasions, we need to modify a linked list drastically so we will sometimes create another linked list and pass it to the old one. For example,
struct node { //let's say we have a linked list storing integers
int data;
node* next;
};
and suppose we already have a linked list storing integers 1,2,3.
node* head; //suppose we already store 1,2,3 in this linked list
node* new_head ; //suppose we make a temporary linked list storing 4,5,6,7
head = new_head; //modifying the original linked list
My Question
If I delete head (the old linked list) before the assignment then the whole program will crash.
Conversely, if I do not delete it, then there will be a memory leak.
Therefore, I am looking for a way to modify the linked list without memory leak.
My attempt
I tried to make a helper function similar to strcpy to do my work.
void passing_node(node*& head1, node* head2){ //copy head2 and paste to head1
node* ptr1 = head1;
for (node* ptr2 = head; ptr2 != nullptr; ptr2 = ptr2->next)
{
if (ptr1 == nullptr){
ptr1 = new node;
}
ptr1->data = ptr2->data;
ptr1 = ptr1->next;
}
}
// note that we assume that the linked list head2 is always longer than head1.
However, I still got a crash in the program and I cannot think of any other way to modify this. Any help would be appreciated.
Easier way to avoid memory leak is to avoid raw owning pointers.
You might use std::unique_ptr (or rewrite your own version):
struct node {
int data = 0;
std::unique_ptr<node> next;
};
You can move nodes.
You can no longer copy nodes (with possible double free issue).
so deep_copy might look like:
std::unique_ptr<Node> deep_copy(const Node* node)
{
if (node == nullptr) return nullptr;
auto res = std::make_unique<Node>();
res->data = node->data;
res->next = deep_copy(node->next.get());
return res;
}
I would suggest preallocating the linked list so it's easy to delete every node in one call. The nodes would then just reference somewhere inside this preallocated memory. For example:
struct Node
{
int value;
Node* next;
};
struct LinkedList
{
Node* elements;
Node* first;
Node* last;
Node* free_list;
LinkedList(size_t size)
{
first = nullptr;
last = nullptr;
elements = new Node[size]{0};
free_list = elements;
for (size_t i = 0; i < size-1; ++i)
free_list[i].next = &free_list[i+1];
free_list[count-1].next = nullptr;
}
~LinkedList()
{
delete[] elements;
}
void Add(int value)
{
if (free_list == nullptr)
// Reallocate or raise error.
// Take node from free_list and update free_list to
// point to the next node in its list.
// Update last node to the new node.
// Update the first node if it's the first to be added.
}
void Free(Node* node)
{
// Search for the node and update the previous and
// next's pointers.
// Update first or last if the node is either of them.
// Add the node to the last place in the free_list
}
};
From here you'll have many strategies to add or remove nodes. As long as you make sure to only add nodes to the allocated elements array, you'll never have any memory leak. Before adding, you must check if the array have the capacity to add one more node. If it doesn't, you either have to raise an error, or reallocate a new the LinkedList, copy over all values, and delete the old one.
It becomes a bit more complicated when the array becomes fragmented. You can use a 'free list' to keep track of the deleted nodes. Basically, a LinkedList of all nodes that are deleted.
Just take notice that my code is incomplete. The basic approach is to create an allocator of some sort from which you can allocate a bulk, use segments of it, and then delete in bulk.

function with return type node* in conjunction with OOP in c++

I need to write a program that takes an instance of a linear linked list and removes all of the items in the list except for the last two items. I'm doing this in c++ using classes, so I'll have 3 files: main.cpp, list.h, and list.cpp. There can be no loops: I can use multiple functions but the traversal part has to be recursive.
I thought about it and what I concluded is this: I'll have to have one public function that I can call from main which will take no arguments, called void lastTwo(). I'll have another private function called node* lastTwo(node *& current, node *& tail) which will be called by lastTwo(), and it will traverse the list recursively and delete the nodes it touches until it reaches the second to last node in the list, and then it will return the address of that node.
Then, when it returns the address of the second to last node in the list, the public function lastTwo() will catch that address and set head equal to it.
The problem I'm having is that I need to do this in vi and compile and run from the command line, and I'm getting a segmentation fault even though I drew a pointer diagram and can't find a problem with my code.
I'm working on this on the student server at my university, and all of the implementation of the data structure except for these two functions have been written by my instructors, so they're all solid. Also, every time you run the a.out file, they've written it to generate a new, random, non-empty linked list, of at least 5 nodes.
I think the problem is related to the function having the return type "node*" , because I tried doing this in visual studio as well and it wouldn't let me have functions of type node*. But, I know that when you don't use classes and just put everything in one file, functions of type node* work.
Here is my list.h:
#include<iostream>
struct node
{
int data;
node* next;
};
class list
{
public:
// these functions were already written by the school and included in the .o file
list();
~list();
void build();
void display();
// my functions
void lastTwo();
private:
node* head;
node* tail;
node* lastTwo(node *& current, node *& tail);
}
And list.cpp:
void list::lastTwo(){
node* current = head;
node * newHead = lastTwo(current, tail);
head = newHead;
delete newHead;
head->next = tail;
}
node* lastTwo(node *& current, node *& tail){
if(current->next == tail){
return current;
}
else if(current->next != tail){
node* temp = current;
current = current->next;
temp->next = NULL;
delete temp;
lastTwo(current, tail);
}
return NULL;
}
Any ideas on what might be the problem, and what the correct way to do this is, would be really appreciated! Thank you
Your problem happens when your recursion unwinds. Most of the calls to lastTwo happen in the else if. That base case is the if which returns current, but the call to lastTwo which triggered the base case is always going to return NULL when the else if ends.
Imagine this is your stack when the base case is reached:
lastTwo // Base case, returns current, but the call below this doesn't do anything with it.
lastTwo // returns null
...
lastTwo // returns null
That NULL is used by the other lastTwo and you get your seg fault.
You might use the following:
void list::lastTwo() {
// Stop work with less than 2 items
if (head == nullptr // 0 items
|| head == tail // 1 item
|| head->next == tail) { // 2 items
return;
}
// pop_front()
auto* next = head->next;
delete head;
head = next;
// loop
lastTwo();
}

Does this cause memory leak when I call the deconstructor?

I have a data structures project I have to do for my Uni class which is to implement a stack with a linked list; simple stuff. We have had some help, code-wise, to show us the correct way to implement such a structure.
Stack class:
class Stack
{
public:
Stack(void)
{
top = NULL; // Initialises defualt top node pointer.
}
~Stack(void)
{
while (NodePop() != NULL){}
}
void Push(int value) // Pushes a new node onto the stack.
{
Node* temp = new Node(value, top); // Creates a temporary node with a value and makes it
// point to the top node as the next node in the stack.
top = temp; // Temporary node becomes the top node in the stack.
}
Node* NodePop(void)
{
/* Remove top node from the stack */
Node* temp = top; // Creates a temporary node to return, sets it to top node.
if (top != NULL) top = top->getNext(); // Points the stacks top node to the next node in the list.
return temp; // Returns a pointer to the popped node still in the heap.
}
int Pop(void) // Pops the top node off of the stack. Returns the nodes value.
{
Node* temp = NodePop();
int valueReturn = 0;
/* Sets the return value */
if (temp != NULL)
{
valueReturn = temp->getVal(); // Set return value to the nodes value if there is a node left.
}
else
{
throw "Stack Empty"; // Throws exception if temp is NULL and stack is empty.
}
delete temp; // Deletes the node entirely from the heap.
return valueReturn;
}
private:
Node* top;
};
Node class:
class Node
{
public:
Node(int value, Node* nextptr = NULL, Node* prevptr = NULL, int currentpriority = 0)
{
/* Set initial variables for the node at creation */
this->value = value;
this->next = nextptr;
this->prev = prevptr;
this->priority = currentpriority;
}
// bunch of getters and setters...
private:
Node* next; // Pointer to the next node.
Node* prev; // Pointer to the previous node.
int priority; // Stores the node priority as a number 0-9.
int value; // Stores the node value for printing.
};
We cannot change any of the classes structure (too my annoyance, NodePop() should be private, but w/e).
So here NodePop() essentially removes the top node from the list but doesn't delete it; it removes all reference to it from the linked list but it never deletes it from the heap, it's only deleted from the heap in Pop(). All good (except for being able to call NodePop() publicly, but again, I'm not allowed to make it private). But when I call the destructor is has to use NodePop(), not Pop().
So does that mean the node is never deleted from the heap when NodePop() runs from the destructor?
If so how would I delete them because it's going to run nodePop() if i have it in a while, do-while, or if statement condition so there will always be one node left undeleted?
Looking at the code in question
~Stack(void)
{
while (NodePop() != NULL){}
}
Node* NodePop(void)
{
/* Remove top node from the stack */
Node* temp = top; // Creates a temporary node to return, sets it to top node.
if (top != NULL) top = top->getNext(); // Points the stacks top node to the next node in the list.
return temp; // Returns a pointer to the popped node still in the heap.
}
Your destructor calls NodePop() until that function returns NULL. Let's look at what NodePop() does. The comment in the code claims that it Creates a temporary node to return That is not true. It creates a pointer to a Node (a Node*) and sets that pointer to point the same place that top does. If top is not null, it sets top to point to top's next node. It the returns temp, which is a pointer to what was originally the top Node.
At no point to you release memory associated with any Node, so yes there is a memory leak.
You can fix the leak by deleting each Node* that you encounter in the destructor that is not NULL.
Indeed, the nodes are not deleted, and this code will leak. You can verify that by using a tool like Valgrind.
I would change the while to something like while (Node *N = NodePop()) delete N;
FYI, this code is definitely not idiomatic C++11. It's basically poorly written C, and I'd expect to find more bugs in it. Your teacher should get a slap on the wrist for presenting C++11 like this :-)

C++ Linked Lists and Pointers to Pointers

First post but I have been a lurker for some time now :)
First, I am attempting to execute this skeleton code in Visual Studio 2015 and it should work as is according to my teacher so I am not sure what else could be wrong client side that may be causing that.
Finally, the overall issue here is I am not sure how to complete the remain commands. I understand the basic concepts of how the pointer to pointers work as well as the linked lists but not completely. My first issue is not helping either.
Any help would be greatly appreciated.
Thanks,
Several
#include <stdio.h>
#include <stdlib.h>
typedef struct _node {
int value;
struct _node *next;
} node;
void append(node**, int);
void prepend(node**, int);
void lprint(node*);
void destroy(node*);
int main(int argc, char **argv)
{
node *head = NULL;
append(&head, 1);
append(&head, 2);
append(&head, 3);
prepend(&head, 0);
prepend(&head, -1);
prepend(&head, -2);
lprint(head);
destroy(head);
return 0;
}
void append(node **head, int value)
{
if (*head == NULL)
{
*head = (node*)calloc(0, sizeof(node));
(**head).value = value;
}
else
{
node *temp;
for (temp = *head; (*temp).next != NULL; temp = temp->next);
(*temp).next = (node*)calloc(0, sizeof(node));
(*temp).(*next).value = value;
}
}
void prepend(node **head, int value)
{
}
void lprint(node *head)
{
node *temp;
for (temp = head; temp != NULL; temp = temp->next)
{
printf("%d ", temp->value);
}
printf("\n");
}
void destroy(node *head)
{
}
I was able to compile and run your code after changing this line:
(*temp).(*next).value = value;
to this:
(*temp).next->value = value;
When I ran it, it printed out:
1 2 3
... which is what I would expect, given that prepend() isn't implemented.
I could write an implementation of prepend() and post it here, but I don't want to risk doing your homework for you; instead I'll just describe how prepend() ought to work.
For the case where head is NULL, prepend() can do the exact same thing that append() does: allocate a node and set head to point to that node.
For the other case, where head is non-NULL (because the list is non-empty), it's pretty easy too -- even easier than the append() implementation. All you need to do is allocate the new node, set the new node's next pointer to point to the existing head node (*head), and then set the head pointer (*head) to point to the new node.
The destroy() function can work with a loop very similar to the one in your lprint() function, with one caveat -- you have to grab the next pointer out of a given node (and store it into a local variable) before you free() the node, because if you free the node first and then try to read the next-pointer from the already-freed node, you are reading already-freed memory which is a no-no (undefined behavior) and will cause bad things (tm) to happen.

Coding a function to copy a linked-list in C++

I need to implement an auxilliary function, named copyList, having one parameter, a pointer to a ListNode. This function needs to return a pointer to the first node of a copy of original linked list. So, in other words, I need to code a function in C++ that takes a header node of a linked list and copies that entire linked list, returning a pointer to the new header node. I need help implementing this function and this is what I have right now.
Listnode *SortedList::copyList(Listnode *L) {
Listnode *current = L; //holds the current node
Listnode *copy = new Listnode;
copy->next = NULL;
//traverses the list
while (current != NULL) {
*(copy->student) = *(current->student);
*(copy->next) = *(current->next);
copy = copy->next;
current = current->next;
}
return copy;
}
Also, this is the Listnode structure I am working with:
struct Listnode {
Student *student;
Listnode *next;
};
Note: another factor I am running into with this function is the idea of returning a pointer to a local variable.
The first question you need to ask yourself is what the copy semantics are. In particular, you're using a Student* as node contents. What does copying node contents mean? Should we copy the pointer so that the two lists will point to (share) the same student instances, or should you perform a deep copy?
struct Listnode {
Student *student; // a pointer? shouldn't this be a `Student` object?
Listnode *next;
};
The next question you should ask yourself is how you will allocate the nodes for the second list. Currently, you only allocate 1 node in the copy.
I think you code should look more like:
Listnode *SortedList::copyList(Listnode *L) {
Listnode *current = L;
// Assume the list contains at least 1 student.
Listnode *copy = new Listnode;
copy->student = new Student(*current->student);
copy->next = NULL;
// Keep track of first element of the copy.
Listnode *const head = copy;
// 1st element already copied.
current = current->next;
while (current != NULL) {
// Allocate the next node and advance `copy` to the element being copied.
copy = copy->next = new Listnode;
// Copy the node contents; don't share references to students.
copy->student = new Student(*current->student);
// No next element (yet).
copy->next = NULL;
// Advance 'current' to the next element
current = current->next;
}
// Return pointer to first (not last) element.
return head;
}
If you prefer sharing student instances between the two lists, you can use
copy->student = current->student;
instead of
copy->student = new Student(*current->student);
This is an excellent question since you've done the bulk of the work yourself, far better than most "please do my homework for me" questions.
A couple of points.
First, what happens if you pass in an empty list? You probably want to catch that up front and just return an empty list to the caller.
Second, you only allocate the first node in the copy list, you need to do one per node in the original list.
Something like (pseudo-code (but C++-like) for homework, sorry):
# Detect empty list early.
if current == NULL:
return NULL;
# Do first node as special case, maintain pointer to last element
# for appending, and start with second original node.
copy = new node()
last = copy
copy->payload = current->payload
current = current->next
# While more nodes to copy.
while current != NULL:
# Create a new node, tracking last.
last->next = new node()
last = last->next
# Transfer payload and advance pointer in original list.
last->payload = current->payload
current = current->next
# Need to terminate new list and return address of its first node
last->next = NULL
return copy
And, while you're correct that you shouldn't return a pointer to a local stack variable, that's not what you're doing. The variable you're returning points to heap-allocated memory, which will survive function exit.
I have been trying to do the same thing. My requirements were:
1. Each node is a very basic and simple class (I moved away from the struct model).
2. I want to create a deep copy, and not just a pointer to the old linked list.
The way that I chose to do this is with the following C++ code:
template <class T>
Node <T> * copy(Node <T> * rhs)
{
Node <T> * current = new Node<T>();
Node <T> * pHead = current;
for (Node <T> * p = rhs; p; p = p->pNext)
{
Node <T> * prev = current;
prev->data = p->data;
if (p->pNext != NULL)
{
Node <T> * next = new Node<T>();
prev->pNext = next;
current = next;
}
else
{
prev->pNext = NULL;
}
}
return pHead;
}
This works well, with no errors. Because the "head" is a special case, there is a need for my implementation of a "current" pointer.
The statement
copy->next = current->next
is wrong. You should do
Create the first node copy here
copy->student = current->student;
copy->next = NULL;
while(current->next!=NULL)
{
Create new node TEMP here
copy->next = TEMP;
TEMP->student = current->student;
TEMP->next = NULL;
copy = TEMP;
}
Since you need a copy of the linked list, you need to create a new node in the loop while traversing through the original list.
Listnode *startCopyNode = copy;
while (current != NULL) {
*(copy->student) = *(current->student);
copy->next = new Listnode;
copy = copy->next;
current = current->next;
}
copy->next = NULL;
return startCopyNode;
Remember to delete the nodes of linked list.
#pat, I guess you will get a seg_fault, because you create memory only once. You need to create memory(basically call 'new') for each and every node. Find out, where you need to use the 'new' keyword, to create memory for all the nodes.
Once you are done with this, you need to link it to the previous node, since its a singly linked list, you need to maintain a pointer to the previous node. If you want to learn and should be able to remember all life, don't see any of the code mentioned above. Try to think the above mentioned factors and try to come up with your own code.
As others have pointed out, you need to call new for each node in the original list to allocate space for a copy, then copy the old node to the new one and update the pointer in the copied node.
another factor I am running into with this function is the idea of returning a pointer to a local variable.
You are not returning a pointer to a local variable; when you called new, you allocated memory on the heap and are returning a pointer to that (which of course means that you need to remember to call delete to free it when you are done with the new list, from outside the function).