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.
Related
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.
I've successfully implemented a recursive PrintList method, so I don't understand why a recursive destructor won't work:
//recursively deleting nodes in a doubly linked list
LinkedList::~LinkedList()
{
if (Head == 0) //base case
{
Tail = 0; //fixing the dangling Tail pointer doesn't seem to fix the error...
return;
}
else
{
Node* temp = Head;
Head = Head->getNext();
cout << "deleting " << temp->getNumber() << endl;
delete temp;
delete this;
}
}
When debugging, I get the _Block_Type_Is_Valid (pHead->nBlockUse) Error after calling the LinkedList destructor, just before the program could finish up "nicely". This is past "return 0;" in main.cpp, and I stepped through the destructor code shown above with no problem, and indeed the destructor gave me all the correct test messages and worked as intended.
Even more frustrating was that I can't locate what caused this error: I tried to "step over" beyond the LinkedList destructor code, but I got the message from VS: "Source Not Available: Source information is missing from the debug information for this module". I was thinking the dangling Tail pointer (which points at a random memory after the destructor executes) might be a problem, so I set "Tail=0;" before returning from the base case, but that doesn't seem to be working.
The only way I can suppress this error is by either:
constructing a LinkedList then simply ending the program without adding any nodes into it (no problem deleting an empty LinkedList), or
making my LinkedList in main dynamically allocated, and ending the program without manually deleting it (skipping the entire LinkedList destructor)
What is the problem here? Help!!
UPDATE: My fantastic CS professor pointed out my problem:
"When the destructor exits and attempts the automatic deallocation of the node, it has already been destroyed by the delete this statement.
When the delete keyword is used, it initiates the destructor and then deallocates the memory."
So like #0x499602D2 pointed out, "delete this" was the problematic line, but it had nothing to do with whether my LinkedList was NEWed and then deleted or statically created at compile time then automatically destroyed. Essentially it was caused by the behavior of the destructor.
The solution therefore is: changing "delete this;" to "this->~LinkedList();"
Only by "this->~LinkedList();" can I make recursive calls to the destructor without really "deleting" the calling object; instead it'll be destroyed when the destructor exits and does the automatic deallocation, avoiding the mistake of deleting it again.
More details:
Here's my implementation of Node (doubly linked). It derives from a singly-linked BaseNode class:
//Specification file for BaseNode class
#ifndef BASENODE_H
#define BASENODE_H
#include <iostream>
class BaseNode
{
protected:
char * name;
int number;
BaseNode * next;
public:
//default constructor
BaseNode();
//overloaded constructor
BaseNode(const char *, int);
//destructor
~BaseNode() {
std::cout << "name is: " << name << '\n';
delete[] name;
}
//getter functions
char * getName() const { return name; }
int getNumber() const { return number; }
BaseNode* getNext() { return next; }
//setter functions
void setNumber(int num){ number = num; };
void setNext(BaseNode* ptr) { next = ptr; }
};
#endif
//Implementation file for BaseNode class
#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif
#include <cstring>
#include "BaseNode.h"
//default constructor
BaseNode::BaseNode()
{
name = 0;
number = 0;
next = 0;
}
//overloaded constructor
BaseNode::BaseNode(const char * str, int num)
{
roman = new char[strlen(str) + 1]; //set aside one more character for null terminator
strcpy(name, str);
number = num;
}
Then my Node class inherits the BaseNode class:
#ifndef Node_H
#define Node_H
#include "BaseNode.h" //include the base class for inheritance to work
class Node : public BaseNode
{
protected:
Node * prev;
Node * next;
public:
Node() : BaseNode()
{ prev = next = 0; }
Node(const char * namestr, int num) : BaseNode(namestr, num)
{ prev = next = 0; }
//empty destructor; the BaseNode destructor automatically gets called from here and does the job
~Node() { }
//getter functions and setter functions are all inherited from BaseNode, except that....
//the BaseNode version of getNext and setNext won't work for our Node class
Node* getNext() const { return next; }
void setnext(Node* pointer) { next = pointer; }
Node* getPrev() const { return prev; }
void setPrev(Node* pointer) { prev = pointer; }
};
#endif
I always seem to get in trouble when I'm deleting all nodes from a tree. I am trying to release all the memory I allocated when creating a trie tree.
I am suppose to create a function remove_all
Is it enough to delete just the "root"
something like this:
void PrefixStringSet::remove_all(NodePtr node)
{
delete root;
}
Or do I have to delete each node with something like this:
void PrefixStringSet::remove_all(NodePtr node)
{
if(!root)
{
return;
}
remove_all(root->children);
delete root;
}
Obviously neither of these are working or I wouldn't be here :).
Other question. Do I have to call the remove_all function in my main function if my destructor is implemented like this
PrefixStringSet::~PrefixStringSet()
{
remove_all(root);
}
Or does the destructor automatically delete the trees/nodes I create?
Edit
struct TrieNode
{
TrieNode(bool present = false);
bool is_leaf();
bool present;
TrieNode* children[ALPHABET_SIZE];
};
class PrefixStringSet
{
public:
// Creates an empty prefix string set.
PrefixStringSet();
~PrefixStringSet();
bool insert(string s);
bool contains(string s);
private:
NodePtr root;
void remove_all(NodePtr node);
};
typedef TrieNode* NodePtr;
Deleting only root is not enough: when deleting a root, you should check whether its children aren't empty, and if they are not empty, recursively delete them. C++ doesn't have garbage collector to do the work for you :)
If your remove_all method is within the destructor of the wrapper object, then you don't have to call it separately.
You should write a remove method in all classes you want to delete at runtime.
So you can delete a tree with little care about garbage collection.
It's easy to use pointer in this way:
class a
{
public:
a(){}
~a(){remove();}
init(int v){
var = new int;
*var=v; }
remove(){delete var;}
private:
int *var;
};
class b
{
public:
b(){}
~b(){remove();}
init(int v){
var = new a;
var->init(v); }
remove(){
var->remove();
delete var; }
private:
a *var;
};
To answer your question: No, deleting root is not enough.
edit: sry i made a mistake at a:init(). I forgot to derefer the pointer.
In Cpp:
void deleteAll(Node* curNode) {
for (int i = 0; i < 26; i++) {
if (NULL != curNode->child[i]) {
deleteAll(curNode->child[i]);
}
}
delete curNode;
}
deleteAll(root);
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;
}
}
};
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 :)