How to 'delete' this linked list from memory? - c++

I've created class for building a linked list. The class declaration is as follows:
class LinkedList
{
private:
int data;
LinkedList *next;
static int count;
public:
LinkedList(void);
~LinkedList(void);
int insert(int arg);
int remove(int arg);
bool find(int arg);
};
How can I make sure all nodes of this linked list are deleted? The destructor is made responsible for deleting just one node. I used to make linked list like this previously but never thought about clearing the memory.

The naive implementation
~LinkedList() {delete next;}
will do the right thing - delete will call the destructor on the next element, which will delete the one following it, and so on, to delete the whole list.
However, this means that the destructors are called recursively, so that deleting a very long list could cause a stack overflow. Iteration might be better:
~LinkedList() {
while (LinkedList * head = next) {
next = head->next;
head->next = nullptr;
delete head;
}
}
As noted in the comments, it might be more appropriate to have separate List and Node classes, with List responsible for memory management, and Node a simple aggregate containing the data and the link. Then there's less scope for error in the destructor, as it doesn't need to nullify any pointers to prevent recursion:
struct Node {
int data;
Node * next;
};
struct List {
Node * head;
~List() {
while (Node * victim = head) {
head = victim->next;
delete victim;
}
}
};

Related

Linked Lists Append To Tail

I am trying to create an appendToTail function which will add a node to the end of a singly linked list.
I am having trouble in adding a node if the head is NULL(the linked list is empty)
class Node {
private:
Node* next;
int data;
public:
Node(int d, Node* n = NULL)
: data(d)
, next(n)
{
}
void appendToTail(int);
//other trivial functions(getters and setters etc. ) defined and
//declared
};
void Node::appendToTail(int d)
{
Node* end = new Node(d);
Node* n = this;
if (n == NULL)
n = end;
else {
while (n->next != NULL)
n = n->next;
n->next = end;
n->next->next = NULL;
}
end = NULL;
delete end;
}
int main()
{
Node* n = NULL;
n->appendToTail(5);
std::cout << n->getData(); //getData() is a function which
//retrieves the Data member variable
}
I am expecting to get 5 but I am getting an error which appears to be caused because my node remains null.
Now with modern C++ idioms we use smart pointers instead of raw pointers, it gives you the benefit of RAII (Resource acquisition is initialization) mechanism. In addition if you want an elegant solution to your problem you should introduce a List class with which you can express more clearly the concept of an empty list. It would give something like this:
#include <memory>
#include <iostream>
class List
{
public:
class Node
{
private:
std::shared_ptr<Node> next;
int data;
public:
Node(int d):next(nullptr),data(d){}
inline int getData() const {return data;}
inline std::shared_ptr<Node> getNext() const {return next;}
friend List;
};
List():head(nullptr),tail(nullptr){}
void appendToTail(int );
inline std::shared_ptr<Node> getHead() const {return head;}
inline std::shared_ptr<Node> getTail() const {return tail;}
private:
std::shared_ptr<Node> head;
std::shared_ptr<Node> tail;
};
void List::appendToTail(int d)
{
auto newTail = std::make_shared<Node>(d);
if (head == nullptr)
{
head = tail = newTail;
}
else
{
tail->next = newTail;
tail = newTail;
}
}
int main()
{
List l;
l.appendToTail(5);
std::cout<<l.getHead()->getData();
}
But you should definitely prefer std::list<T> or std::vector<T>.
Unfortunately there several errors with your approach. Semantic errors and a logical error with your interpretation of a linked list. Let's start with your initial misunderstanding. You cannot add a new tail to an empty list. Because it is emtpy. Meaning, not yet existing. Only if some object is existing/instantiated you can add a tail. You cannot add something to not existing stuff. So your idea to start with a Node* n = nullptr cannot work logically.
Additionally you are dereferencing a nullptr (major bug). That is also the main problem of your code. Nothing works. You need an instantiated object, before you can call it's member functions.
So before you can populate the list, you need to create/instantiate it initially. So you need to explicitly create the first node in your main function with
Node* n = new Node (5)
Then the list is existing and from now on you can add new members with calling appendToTail.
There are more semantic errors in your code which have luckily no side effects.
You must not delete the 'end' variable in your function. You want to keep the newly allocated memory for the new tail. But you introduced an additional sematic error by setting 'end' to nullptr and then call delete. Deleting a nullptr is a noOp and will do nothing. So, although you have a semantic error, this will not cause any trouble.
There is more:
For a pointer to Null you should always use nullptr.
And, your
if (n == NULL)
is always false. Before that, you assigned this to n. This is never NULL. You can delete the if else. Keep the statements from the else, except the
n->next->next = NULL;
That's not necessary. The constructor did that already for you. As explained, the next 2 statements should also be elimanted.
Additionally you may want to read a little more on the concept of linked lists.
I hope I could help a little

AddToTail function in doubly linked list causes core dump

I am currently trying to write a doubly linked list class in c++ language on cygwin64. My addToTail function (to add a node to the end of the list) causes a core dump. I have identified the line of code which does it but cannot work out why.
I have peeled back my code to the simplest form to work out where the problem is. I have identified it as the current->setNext(temp); line.
below is all relevant code
class Node
{
private:
classType data;
Node* next;
Node* previous;
public:
void Node::setData(const valueType& newData)
{
data = newData;
}
void Node::setNext(Node* newNext)
{
next = newNext;
}
void Node::setPrevious(Node* newPrevious)
{
previous = newPrevious;
}
};
class LinkedList
{
private:
Node* tail;
Node* head;
Node* current;
public:
void LinkedList::addToTail(const classType& newTail)
{
Node* temp = new Node;
temp->setData(newTail);
current = tail;
temp->setPrevious(current);
current->setNext(temp);
tail = temp;
delete temp;
}
};
The expected results of the function is to add a new Node onto the end of the list. What happens is it causes a core dump.
(I assume that LinkedList has valid constructors, and assignment operators no shown in the question. If it lacks those, then addToTail treads on undefined behavior from the the start)
public:
void LinkedList::addToTail(const classType& newTail)
{
Node* temp = new Node;
temp->setData(newTail);
...
tail = temp;
delete temp;
}
The last delete makes no sense. It deletes temp, which is the same as deleting tail since tail is still accessible from LinkedList. It will trigger undefined behavior the next time addToTail is called, since it will access the deleted tail here:
temp->setData(newTail);

C++ Will this destructor leak resources?

I wanted to know how to make sure I'm not leaking memory when calling delete on a singly-linked list (implemented by hand, btw).
I created these super basic list,node and person classes to make myself a little bit clearer.
Here you go:
class person {
public:
person();
//something to do like sets gets etc...
virtual ~person();
private:
int id;
person* pplArr[5]; //Dynamically allocated person objs.
};
person::person(){
pplArr[5] = NULL;
}
person::~person(){
for(int i = 0; i < 5; i++)
delete pplArr[i];
}
#include "person.h"
class node {
public:
node(person*, node*);
person* getData();
node* getNext();
void setNext(node*);
virtual ~node();
private:
person* data;
node* next;
};
node::node(person* p, node* n){
data = p;
next = n;
}
person* node::getData(){
return data;
}
node* node::getNext(){
return next;
}
void node::setNext(node* nxt){
next = nxt;
}
node::~node(){
//nothing to delete "manually".
}
#include "node.h"
class list {
public:
list();
node* getFirst();
void insert(person*);
virtual ~list();
private:
node* first;
};
node* list::getFirst(){
return first;
}
void list::insert(person* p){
if(first){
first->setNext(new node(p, NULL));
}
else {
first = new node(p, NULL);
}
}
list::~list(){
node* aux;
while (first){
aux = first->getNext();
delete first;
first = aux;
}
}
Okay, so as you can see we have these 3 classes:
person contains an array of 5 people objects, dynamically allocated:
node contains a pointer to next node, and data which contains the actual person object. and,
list that contains the nodes and manages them.
In order to successfully deallocate all the memory, I need call delete listName, this line will go into each node and call delete for each node, which will in itself call the delete for person.
The delete for person will go into each array slot and call the 'delete' of those persons to release that memory.
After that, it will execute the other deletes that are waiting. From bottom to top.
Is this correct? Are my destructors correct?
I would just like to know how to completely release the memory I allocated if there is a singly-linked list that contains nodes that have objects that have dynamically allocated memory.
I'm very confused, my apologies if this is nonsense or utterly bad implementation.
PS: I don't know if this list works, I just wanted to make a basic linked list to see if you guys could help me understand, so hopefully I can grasp the concept on actual, more complex lists. I am aware that there are linked lists and other data structures readily available on libraries but college teachers ask us to do it this way first.

Should I initialize a struct's variables within the constructor of its containing class?

I have a header file with a class called 'list' and a struct called 'node' within the private part of that class. Together, this class and struct will make up a doubly threaded linked list of winery objects (winery being it's own class). What I'm wondering is if it would be best to implement and de-implement the node struct's variables within the list constructor and deconstructor
(like this example, which throws errors in the compiler):
list::list()
{
struct node
{
item = winery::winery()
nextByName = nullptr;
nextByRating = nullptr;
};
headByName = nullptr;
headByRating = nullptr;
}
list::~list()
{
struct node
{
delete item;
delete nextByName;
delete nextByRating;
};
delete headByName;
delete headByRating;
}
My compiler throws an error when I delete those nodes within the list constructor and deconstructor; so the example above is obviously incorrect in some ways. But it still seems to me that a solution to this could work without this methodology, just not with this exact code.
I'm also curious if it would be better to implement and de-implement the struct separately
(like this):
list::node::node()
{
item = winery::winery()
nextByName = nullptr;
nextByRating = nullptr;
}
list::node::~node()
{
delete item;
delete nextByName;
delete nextByRating;
}
When I delete those elements separately (above), my constructor only throws the error for the delete item;. Do you know why this is? Can you explain why I don't need to delete the winery item? Should I call the winery deconstructor there?
Should I do something entirely different? I've looked online, and in my textbooks, but there really is no clear answer on this. I would really appreciate your guys help, and if you could explain why your solution is the best (if it is the best), I would be extremely grateful. I just started learning C++ a few months ago after all.
By the way, this is what my list.h file looks like:
#include "winery.h"
class list
{
public:
list();
~list();
void addWinery();
void removeWinery();
void displayByRating() const;
void displayByName() const;
void searchByName() const;
private:
struct node
{
winery item;
node * nextByName;
node * nextByRating;
};
node * headByName;
node * headByRating;
};
To initialize, you could do this:
class list
{
public:
list();
// etc.
private:
struct node
{
winery item;
node * nextByName = nullptr;
node * nextByRating = nullptr;
};
node * headByName = nullptr;
node * headByRating = nullptr;
};
And then you do not need the constructor to take any further action.
Your destructor is suspicious though. If each node * is supposed to own the object it is pointing to, then use std::unique_ptr<node> instead of node *. And if it isn't then delete is not the right solution.

List destructor in C++

I've just implemented the Linked List. It works perfectly fine but even tough I've seen notation I am unable to create working destructor on Node, that's why it's unimplemented here in code.
I need to implement working destructor on node
Destructor of List but this one is simple I will just use the destructor from Node class(but I need this one).
Make the List friendly to Node so I will not have to use getNext(), but I think I can
handle it myself(not sure how, but I'll find out).
Please look at the code it is perfectly fine, just will work if you copy it.
#include <cstdio>
#include <cmath>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
class Node {
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
Node(const Node& obiekt) {
this->wrt = obiekt.wrt;
this->next = obiekt.next;
}
~Node() {}
void show() {
cout << this->wrt << endl;
}
int getWrt(){
return this->wrt;
}
Node* getNext(){
return this->next;
}
void setNext(Node* node){
this->next = node;
}
private:
Node* next;
int wrt;
};
class List{
public:
List(int wrt){
this->root = new Node(NULL, wrt);
}
List(const List& obiekt){
memcpy(&this->root,&obiekt.root,sizeof(int));
Node* el = obiekt.root->getNext();
Node* curr = this->root;
Node* next;
while(el != NULL){
memcpy(&next,&el,sizeof(int));
curr->setNext(next);
curr = next;
next = curr->getNext();
el = el->getNext();
/* curr->show();
next->show();
el->show(); */
}
}
void add(int wrt){
Node* node = new Node(NULL, wrt);
Node* el = this->root;
while(el->getNext() != NULL){
//el->show();
el = el->getNext();
}
el->setNext(node);
}
void remove(int index){
Node* el = this->root;
if(index == 0){
//deleting old one
this->root = this->root->getNext();
}
else{
int i = 0;
while(el != NULL && i < index - 1){
// el->show();
el = el->getNext();
i++;
}
if(el!=NULL){
Node* toRem = el->getNext();
Node* newNext = toRem->getNext();
el->setNext(newNext);
//deleteing old one
}
}
}
void show(){
Node* el = this->root;
while(el != NULL){
el->show();
el = el->getNext();
}
}
~List(){}
private:
Node* root;
};
int main(){
List* l = new List(1); //first list
l->add(2);
l->add(3);
l->show();
cout << endl;
List* lala = new List(*l); //lala is second list created by copy cosntructor
lala->show();
cout << endl;
lala->add(4);
lala->remove(0);
lala->show();
return 0;
}
I suggest you to start with implementing destructor of List. Since you dynamically allocated memory by using new, you should free it by using delete. (If you used new[], it would be delete[]):
~List()
{
Node* currentNode = this->root; // initialize current node to root
while (currentNode)
{
Node* nextNode = currentNode->getNext(); // get next node
delete currentNode; // delete current
currentNode = nextNode; // set current to "old" next
}
}
Once you have proper destructor, you should try whether your copy constructor is correct:
List* lala = new List(*l);
delete l; // delete list that was used to create copy, shouldn't affect copy
you will find out that your copy constructor is wrong and also causes your application to crash. Why? Because purpose of copy constructor is to create a new object as a copy of an existing object. Your copy constructor just copies pointers assuming sizeof(Node*) equal to sizeof(int). It should look like this:
List(const List& list)
{
// if empty list is being copied:
if (!list.root)
{
this->root = NULL;
return;
}
// create new root:
this->root = new Node(NULL, list.root->getWrt());
Node* list_currentNode = list.root;
Node* this_currentNode = this->root;
while (list_currentNode->getNext())
{
// create new successor:
Node* newNode = new Node(NULL, list_currentNode->getNext()->getWrt());
this_currentNode->setNext(newNode);
this_currentNode = this_currentNode->getNext();
list_currentNode = list_currentNode->getNext();
}
}
Also your function remove is wrong since it "removes" reference to some Node but never frees memory where this Node resides. delete should be called in order to free this memory.
"I need to implement working destructor on node" - No, you don't. Node itself doesn't allocate any memory, thus it shouldn't free any memory. Node shouldn't be responsible for destruction of Node* next nor cleaning memory where it's stored. Don't implement destructor nor copy constructor of Node. You also want to read this: What is The Rule of Three?
"Make the List friendly to Node so I will not have to use getNext()" - You want to say within Node class, that class List is its friend:
class Node
{
friend class List; // <-- that's it
Note that from these 5 headers that you include your code requires only one: <iostream>.
Also note that writing using namespace std; at the beginning of the file is considered bad practice since it may cause names of some of your types become ambiguous. Use it wisely within small scopes or use std:: prefix instead.
The linked list destructor will be called either when delete is used with a previously allocated pointer to a linked list or when a linked list variable goes out of scope (e.g., a local variable is destroyed when returning from a function).
The destructor for the linked list should be responsible to free the memory you previously reserved for the nodes (i.e., using add operation). So, basically, you need to traverse the list of nodes and apply the delete operation on each one of them. There is a little trick: when you are about to delete a node you must be careful not to lose the pointer to the next element (when a node is deleted you cannot be sure that next member will still be valid).
If you want to create a destructor for your Node, it should be quite simple actually.
Here it is:
class Node {
private:
int wrt;
Node* next;
public:
Node(Node* next, int wrt) {
this->next = next;
this->wrt = wrt;
}
// Your desired destructor using recursion
~Node() {
if ( next != NULL )
delete next;
}
};
It's that simple :)
Basically, right before the Node is deleted, if next is not empty, we delete next, which will again call the destructor of next, and if next->next is not empty, again the destructor gets called over and over.
Then in the end all Nodes get deleted.
The recursion takes care of the whole thing :)