c++ templates and destructor problems - c++

How to deal with memory leaking with template classes in C++?
In this code I defined 4 template classes:
class node and class linked_list make up a doubly linked list
class item and class bag just make up another doubly linked list
These template classes are designed to deal with objects of various classes.
In the main function, I first created a linked_list<string> and a bag<int> and everything is fine.
But when I try to make a bag<linked_list<string>>, problems arise.
I tried to trace back to see what happened, and I saw that in the function push_back in class bag, a destructor of linked_list has been called that erased all the data in the input v. I don't know why that happens.
Note that I overwrote the destructors for all classes and called className.~className() in the main function to prevent memory leaking.
And it does work to prevent memory leaking from ls_1 and bag_1.
I don't know which part of my code is wrong. Can somebody help me?
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
//node and linked_list class make up a doubly linked list
template<class T> class node {
public:
T value;
node<T> * next;
node<T> * previous;
node<T>() { next = nullptr; previous = nullptr; }
node<T>(T v) { value = v; next = nullptr; previous = nullptr; }
~node<T>() { delete next; }
};
template<class T> class linked_list { //doubly linked list
public:
node<T> * head;
node<T> * tail;
linked_list<T>() { head = nullptr; tail = nullptr; }
~linked_list<T>() { delete head; }
void push_front(T v) { //insert an item to the front
node<T> * p = new node<T>(v);
p->next = head;
head = p;
if (tail == nullptr) {
tail = p;
}
}
};
//item and bag class just make up another doubly linked list
template<class X> class item {
public:
X value;
item<X> *next;
item<X> *previous;
item<X>(X v) { value = v; next = nullptr; previous = nullptr; }
~item<X>() { delete next; }
};
template<class X> class bag { //just another doubly linked list
public:
item<X> *last;
item<X> *first;
int num_items;
int size() { return num_items; }
bag() { last = nullptr; first = nullptr; num_items = 0; }
~bag() { delete first; }
void push_back(X v) { //insert an item to the back
item<X> * p = new item<X>(v);
if (num_items == 0) {
last = first = p;
}
else {
last->next = p;
p->previous = last;
last = p;
}
num_items++;
last->next = nullptr;
}
};
int main() {
//When using built-in classes (like strings) as input
//there's no problem at all
linked_list<string> ls_1;
ls_1.push_front("David");
ls_1.push_front("John");
bag<int> bag_1;
bag_1.push_back(1);
bag_1.push_back(2);
//Problems arise here when using user defined classes (linked_list) as input
//I traced back and found out that a destructor has been called
//that erases all the data in the input. Donno how that happens
bag<linked_list<string>> bag_string;
bag_string.push_back(ls_1);
//These lines are to prevent the memory leaking
//I overwrote destructors for linked_list and node class
//otherwise there's still memory leaking
ls_1.~linked_list();
bag_1.~bag();
bag_string.~bag();
_CrtDumpMemoryLeaks();
getchar();
getchar();
}

Implement node, linked_list, item, bag copy constructors and assignments or declare them as deleted. The default versions generated by the compiler do not do the deep copying and that leads to multiple deletes of same objects after they were copied.
Read the rule of three/five/zero for full details.
A bit off-topic, but making a list node delete its siblings is a classic gotcha: for a sufficiently long list it ends up calling ~node<T>() recursively until it exhausts the stack. And this is the reason node pointers cannot be smart-pointers.
A fix would be to have a default destructor for nodes and make the list destroy the nodes in a loop, rather than recursively.
You may also like to use the full list node as a head of the list that points to itself when empty. That removes that nullptr checking logic completely.

I tried to trace back to see what happened, and I saw that in the function push_back in class bag, a destructor of linked_list has been called that erased all the data in the input v
Yes, this happens because your bag::push_back() takes its argument by value. This means it creates a copy of the ls_1 you created in main. You have not specified how to "copy" a list, so the compiler generated this function (a copy constructor) automatically. It can do that because your linked_list only contains two pointers, so the compiler assumes (because you have not told it otherwise) that copying the pointers over is all that is necessary to generate a copy of a linked_list. Unfortunately, that is not correct.
You now have two lists that manage the same contents: The original ls_1 in main() and the function argument v in push_back() - they both contain the same pointers.
Then the same thing happens again in your item constructor: You make a local copy of the list that holds the same pointers as the first two.
You now have several list objects pointing to the same data. Each one will try to destroy the data once it dies. This results in undefined behavior.
To correct this, you need to figure out how copying of a list should work. This is (in part) what the rule linked in the other comment is about: If the destructor of your class is not trivial (i.e. the compiler-generated version would not be sufficient, most likely because you need to release a resource like allocated memory), you should/must always care about how to handle your class being copied around. The various mechanisms that may invoke copy-like behavior (assignment, copy constructor, plus move versions in newer C++) need to be specified (or forbidden) by you.

Related

Returning a pointer or reference to my current object from a insert_node function in a linked list program

I'm a beginner in c++. and I was writing a link list in which I can call my function for inserting nodes like this:
(assuming a and b and c are data which I want to insert in link list.
list.insert(a)->insert(b)->insert(c);
and I did it like this:
#include <iostream>
using namespace std;
class Node {
public:
char letter;
Node* next;
};
class link_list {
private:
Node* head;
public:
link_list() {
head = NULL;
}
link_list* insertNewNode(char item);
};
link_list* link_list::insertNewNode(char item) {
Node* temp;
temp = new Node;
temp->letter = item;
temp->next = head;
head = temp;
return this;
}
int main() {
link_list list;
list.insertNewNode('a')->insertNewNode('b')->insertNewNode('c');
return 0;
}
in my insertNewNode function I'm returning a pointer to my current object.and it's working fine ,however I'm not sure if my method is right?
But I should also explain what happen , if instead of returning a pointer or reference to my current object ,I return my current object.
so I tried this:
class Node {
public:
char letter;
Node* next;
};
class link_list {
private:
Node* head;
public:
link_list() {
head = NULL;
}
link_list insertNewNode(char item);
};
link_list link_list::insertNewNode(char item) {
Node* temp;
temp = new Node;
temp->letter = item;
temp->next = head;
head = temp;
return *this;
}
int main() {
link_list list;
list.insertNewNode('a')->insertNewNode('b')->insertNewNode('c');
return 0;
}
and then I received an error which said list should be a pointer ,so I changed my main to:
int main() {
link_list *list;
list = new link_list;
list->insertNewNode('a')->insertNewNode('b')->insertNewNode('c');
return 0;
}
but I'm still receiving this error which said here list->insertNewNode('a')->insertNewNode('b')->insertNewNode('c'); expression must have a pointer type and these two errors:
1.type 'link_list' does not have an overloaded member 'operator ->'
2.'->link_list::insertNewNode': left operand has 'class' type, use '.'
so here is my questions for purpose of calling insert function like this list.insert(p1)->insert(p2)->insert(p3);, is my way in first program right ? and also is it even possible to return my current object for this purpose? and what would happen if I return current object?
PS:sorry for long question and also thanks in advance for your help.
Well, there's nothing criminal in your current method returning a pointer. Not something done very often, still quite compilable.
More idiomatic would be to return current object by-reference:
link_list &insert(char elem) {
return *this;
}
Your initial problem was that you changed method's return type, but retained -> in main(). If you change insert's return type to reference from pointer, then chained calls should be done via ., as you're working with objects and references to them, not with pointers.
Returning a copy of current object from a setter is not something that should be done, especially if you manage private resources on your own and haven't defined a proper copy constructor yet. Rather return a reference.
Your method seems fine. You are doing
link_list* insertNewNode(char) {
// ...
return this;
}
so that you can chain the insertions like this
list.insertNewNode('a')->insertNewNode('b')->insertNewNode('c');
You could also return a reference to the link_list, like this
link_list& insertNewNode(char) {
// ...
return *this;
}
and now chaining the insertions looks like this
list.insertNewNode('a').insertNewNode('b').insertNewNode('c');
Note that you shouldn't do something like
link_list insertNewNode(char) {
// ...
return *this;
}
because this will compile, but you would be returning a copy of the linked list, and the chaining would simply not work.
If your nodes would be added to the tail, the default copy constructor would make it appear as if chaining works, because the original link_list would see all Nodes added to the copy.
In your implementation, you are adding Nodes at the head, so the original link_list doesn't see Nodes added to the copy, and so the chaining doesn't appear to work. This is good, because the copies would leak the memory they allocate, even if you write a proper destructor.

Establishing an Entry Class for a Linked List

I have a new project where I am creating a class for an entry in a doubly linked list. I am utilizing object-oriented style, which I have limited experience with. The constructors and functions were defined in a separate file.
Header File:
#ifndef LISTENTRY_H_JDP
#define LISTENTRY_H_JDP
#include "DATAClass.h"
#include <iostream>
using namespace std;
typedef DATAClass l;
typedef class LISTEntry *listptr;
class LISTEntry
{
DATAClass data;
listptr prev;
listptr next;
public:
LISTEntry();
LISTEntry(DATAClass l);
LISTEntry(LISTEntry &le);
~LISTEntry();
LISTEntry getNext();
void setNext();
LISTEntry getPrev();
void setPrev();
DATAClass getData();
void setData(DATAClass d);
};
#endif // LISTENTRY_H_INCLUDED
Implementation File:
#include "LISTEntry.h"
LISTEntry::LISTEntry()
{
data = data;
prev = NULL;
next = NULL;
}
LISTEntry::LISTEntry(DATAClass l) //take an item of type l and convert it into a LISTEntry
{
data = l;
prev = NULL;
next = NULL;
}
LISTEntry::LISTEntry(LISTEntry &le)
{
data = le.getData();
prev = le.getPrev();
next = le.getNext();
}
LISTEntry::~LISTEntry()
{
}
LISTEntry LISTEntry::getNext()
{
return *next;
}
void LISTEntry::setNext()
{
next = new LISTEntry;
}
LISTEntry LISTEntry::getPrev()
{
return *prev;
}
void LISTEntry::setPrev()
{
prev = new LISTEntry;
}
DATAClass LISTEntry::getData()
{
return data;
}
void LISTEntry::setData(DATAClass d)
{
data = d;
}
The issue is my copy constructor, LISTEntry(LISTEntry &le). So far, I receive the error:
cannot convert 'LISTEntry' to 'listptr {aka LISTEntry*}'
I am also unsure about the get and set functions. I want them to link to new entries of the same type in the list. I guess I am having trouble with the implementation of pointers in the constructor. Can anyone help out?
You could solve the problem by removing the copy constructor, but this hides the problem that caused the error.
Unless l is poorly written (violates the Rules of Three or Five), there is no need for a copy constructor or destructor in LISTEntry. LISTEntry has no special resources of its own and should be able to observe the Rule of Zero. If l is broken, fix l, do not inflict its flaws on other classes.
But this is not what you want to do for a couple reasons.
The underlying problem causing the error message is prev = le.getPrev(); is attempting to assign a copy of the source's LISTEntry's previous node to the new LISTEntry's pointer to the previous node.
prev needs the address of a LISTEntry, not a LISTEntry.
In a linked list LISTEntry LISTEntry::getNext()and LISTEntry LISTEntry::getPrev() should almost certainly not return a copy of the node pointed at. You want to return the pointer. If you do not, you will find that iterating through the linked list is an adventure. You'll be operating on, possibly modifying, copies of nodes rather than the originals. Chaos ensues.
Change them to LISTEntry * LISTEntry::getNext() and remove the dereference in the return statement.
This solves the error, and a few more you hadn't found yet, but leaves you with a different problem, and the same one you'd have if you removed the copy constructor. You now have two LISTEntry with the same prev and next. This can make for an unstable list. With the copy you can blow the crap out of the original's list. Not cool. Be careful. You are actually better off NOT copying the the links and making the copy constructor:
LISTEntry::LISTEntry(const LISTEntry &le) // make everything const until proven otherwise
{
data = le.data; // this is a member function so it can access private variables
// no need for the accessor function
prev = nullptr;
next = nullptr;
}
You also need/want an assignment operator
LISTEntry & operator=(const LISTEntry &le)
{
if (this != &le)
{
data = le.data;
prev = nullptr;
next = nullptr;
}
}
You should also discuss
void LISTEntry::setNext()
{
next = new LISTEntry;
}
with your rubber duck. Ducky wants to know do you plan to link an existing node if you always create a new one? This will make it really hard to insert, remove and sort.

How is this singly linked list destructor causing an infinite loop?

I wrote a singly linked list implementation using a struct. It is not part of an outer class that manages the operations on the list. Instead all of the operations are handled directly with the Nodes.
I understand that if the struct definition was part of a class, say ListManager, calling the destructor on a ListManager instance would just require one to iterate through the linked list managed by the class and delete each Node.
However, since this linked list is not part of an outer class and manages all of the operations itself I am a bit confused as to how to write the destructor.
Version 1 works well, its a recursive call that goes through the list and frees and memory associated with each Node.
Version 2 caused an infinite loop. I don't understand why, as this is one way that I would implement the destructor for a container class that manages the Node linked list.
Version 3 works well but is too verbose.
I ran all three versions using valgrind and python tutor to check for leaks and other issues.
Any help explaining why Version 2 does not work and why it is incorrect to implement the destructor in such a way is appreciated!
Struct Linked List
#include <iostream>
#include <string>
using namespace std;
struct Node
{
int id;
Node* next;
Node(int newId = 0, Node* newNext = NULL)
: id(newId), next(newNext) { }
};
Destructor Version 1
~Node()
{
if (next != NULL)
delete next;
}
Destructor Version 2
~Node()
{
Node* lead = this;
Node* follow = this;
while (follow != NULL)
{
lead = lead->next;
delete follow;
follow = lead;
}
}
Destructor Version 3
~Node()
{
Node* lead = this;
Node* follow = this;
if (follow != NULL)
{
lead = lead->next;
delete follow;
follow = lead;
}
}
Main
int main()
{
Node* head = NULL;
head = new Node(23, head);
head = new Node(54, head);
head = new Node(81, head);
head = new Node(92, head);
delete head;
return 0;
}
In version 2, you have written a loop that clears up the entire list in one destructor call by looping through the list and deleting every element. However, what happens is not that you have just one destructor call. Every time an element is deleted, that calls the destructor again.
So in the end, the delete follow translates to delete this (because follow = this;) for the first invocation. This then causes the destructor of the first node to be called again, causing the endless loop.
The following nodes would be destroyed multiple times, leading to undefined behavior, but it's not even getting there because of that infinite loop.
You only need each Node to delete (at most) one other Node, to eventually delete all the nodes. You re-assigning of local pointers does not affect the structure of the list.
Both 2 and 3 are delete this, which is suspicious at the best of times, plus some irrelevant ceremony, in the destructor. They are both undefined behaviour, deleting the same object (at least) twice.
Your first attempt is close.
Instead of confusing yourself with copying around pointer values, just use an owning pointer type, like std::unique_ptr.
struct Node
{
int id;
std::unique_ptr<Node> next;
Node(int id = 0, std::unique_ptr<Node> next = {})
: id(id), next(std::move(next)) { }
// correct destructor is implicit
};

Unique Pointer attempting to reference a deleted function

Hello I am trying to use pointers and learning the basics on unique pointers in C++. Below is my code I have commented the line of code in main function. to debug the problem However, I am unable to do so. What am I missing ? Is my move() in the insertNode() incorrect ? The error I get is below the code :
#include<memory>
#include<iostream>
struct node{
int data;
std::unique_ptr<node> next;
};
void print(std::unique_ptr<node>head){
while (head)
std::cout << head->data<<std::endl;
}
std::unique_ptr<node> insertNode(std::unique_ptr<node>head, int value){
node newNode;
newNode.data = value;
//head is empty
if (!head){
return std::make_unique<node>(newNode);
}
else{
//head points to an existing list
newNode.next = move(head->next);
return std::make_unique<node>(newNode);
}
}
auto main() -> int
{
//std::unique_ptr<node>head;
//for (int i = 1; i < 10; i++){
// //head = insertNode(head, i);
//}
}
ERROR
std::unique_ptr>::unique_ptr(const std::unique_ptr<_Ty,std::default_delete<_Ty>> &)' : attempting to reference a deleted function
Aside from other small problems, the main issue is this line:
return std::make_unique<node>(newNode);
You are trying to construct a unique pointer to a new node, passing newNode to the copy constructor of node. However, the copy constructor of node is deleted, since node contains a non-copyable type (i.e. std::unique_ptr<node>).
You should pass a std::move(newNode) instead, but this is problematic since you create the node on the stack and it will be destroyed at the exit from the function.
Using a std::unique_ptr here is a bad idea in my opinion, since, for example, to print the list (or insert into the list), you need to std::move the head (so you lose it) and so on. I think you're much better off with a std::shared_ptr.
I was having the same problem and indeed using a shared_ptr works.
Using the smart pointer as an argument in the function copies the pointer (not the data it points to), and this causes the unique_ptr to reset and delete the data it was previously pointing at- hence we get that "attempting to reference a deleted function" error. If you use a shared_ptr this will simply increment the reference count and de-increment it once you are out of the scope of that function.
The comments in the answers above suggest that using a shared_ptr is baseless. These answers were written before the C++17 standard and it is my understanding that we should be using the most updated versions of the language, hence the shared_ptr is appropriate here.
I don't know why we have to expose node type to user in any case. Whole thingamajig of C++ is to write more code in order to write less code later, as one of my tutors said.
We would like to encapsulate everything and leave no head or tail (pun intended) of node to user. Very simplistic interface would look like:
struct list
{
private:
struct node {
int data;
std::unique_ptr<node> next;
node(int data) : data{data}, next{nullptr} {}
};
std::unique_ptr<node> head;
public:
list() : head{nullptr} {};
void push(int data);
int pop();
~list(); // do we need this?
};
The implementation does something what Ben Voigt mentioned:
void list::push(int data)
{
auto temp{std::make_unique<node>(data)};
if(head)
{
temp->next = std::move(head);
head = std::move(temp);
} else
{
head = std::move(temp);
}
}
int list::pop()
{
if(head == nullptr) {
return 0; /* Return some default. */
/* Or do unthinkable things to user. Throw things at him or throw exception. */
}
auto temp = std::move(head);
head = std::move(temp->next);
return temp->data;
}
We actually need a destructor which would NOT be recursive if list will be really large. Our stack may explode because node's destructor would call unique_ptr's destructor then would call managed node's destructor, which would call unique_ptr's destructor... ad nauseatum.
void list::clear() { while(head) head = std::move(head->next); }
list::~list() { clear(); }
After that default destructor would ping unique_ptr destructor only once for head, no recursive iterations.
If we want to iterate through list without popping node, we'd use get() within some method designed to address that task.
Node *head = list.head.get();
/* ... */
head = head->next.get();
get() return raw pointer without breaking management.
How about this example, in addition to the sample code, he also mentioned some principles:
when you need to "assign" -- use std::move and when you need to just traverse, use get()

Using the destructor to free linked objects

I have a class called "node". I link a bunch of node objects together to form a linked list. When the "node" destructor is called, it only deletes the first node. How do I iterate through the entire linked list of nodes and delete each node object?
Here is the class definition:
class Node
{
private:
double coeff;
int exponent;
Node *next;
public:
Node(double c, int e, Node *nodeobjectPtr)
{
coeff = c;
exponent = e;
next = nodeobjectPtr;
}
~Node()
{
printf("Node Destroyed");
}
The destructor is called by invoking delete on the pointer to the first node of the linked node list.
Since you don't know how many nodes there are in a list, if you do not have firm bounds on that it's not a good idea to invoke destructors recursively, because each call uses some stack space, and when available stack space is exhausted you get Undefined Behavior, like a crash.
So if you absolutely want to do deallocate following nodes in a node's destructor, then it has to first unlink each node before destroying it.
It can go like this:
Node* unlink( Node*& p )
{
Node* result = p;
p = p->next;
result->next = nullptr;
return result;
}
Node::~Node()
{
while( next != nullptr )
{
delete unlink( next );
}
}
But better, make a List object that has ownership of the nodes in a linked list.
Of course, unless this is for learning purposes or there is a really good reason to roll your own linked list, just use a std::vector (and yes I mean that, not std::list).
How do I iterate through the entire linked list of nodes and delete each node object?
It would be cleaner if you had a separate class to manage the entire list, so that nodes can be simple data structures. Then you just need a simple loop in the list's destructor:
while (head) {
Node * victim = head;
head = victim->next; // Careful: read this before deleting
delete victim;
}
If you really want to delegate list management to the nodes themselves, you'll need to be a bit more careful:
while (next) {
Node * victim = next;
next = victim->next;
victim->next = nullptr; // Careful: avoid recursion
delete victim;
}
Under this scheme, you'll also need to be careful when deleting a node after removing it from the list - again, make sure you reset its pointer so it doesn't delete the rest of the list. That's another reason to favour a separate "list" class.