linked list destructor with std::move c++ - c++

I'm learning data structures in C++;
I've written a destructor for a linked list as follows:
~List(){
Node* temporary = new Node;
Node* node = head;
while(node != nullptr){
temporary = node;
node = node->next;
delete temporary;
}
}
But then I realized that I can do:
~List(){
Node* node = head;
while(node != nullptr){
node = std::move(node->next);
}
}
Avoiding creating a temporary object, I tried it and worked fine, but I don't know if it is okay, I didn't find a destructor like this in any other place.

std::move doesn't do anything by it's own, it only cast something to rvalue.
How the rvalue is used is determined by the function that accept it, and assignment of raw pointer does nothing different than copy in that case.
But for example, if you're using std::unique_ptr, the operator=(unique_ptr&&) would delete the original data after assignment*.
so if you're using something like
#include <memory>
struct Node{
std::unique_ptr<Node> next;
// possibly move List destructor here
// i.e. destruct a Node would safely remove all sub-node non-recursively
};
struct List{
std::unique_ptr<Node> head;
// write destructor to prevent deep recursion
~List(){
while(head) head = std::move(head->next); // current head is deleted after assignment
}
};
then it would work
*btw, self-assignment is safe because it's actually effectively reset(r.release())

This code snippet
~List(){
Node* temporary = new Node;
Node* node = head;
while(node != nullptr){
temporary = node;
node = node->next;
delete temporary;
}
}
produces a memory leak due to this unneeded memory allocation
Node* temporary = new Node;
In this code snippet
~List(){
Node* node = head;
while(node != nullptr){
node = std::move(node->next);
}
}
neither memory is freed. Only the pointer node is reassigned until it will be equal to a null pointer. So there are again numerous memory leaks.
If you do not want to use an intermediate variable then the destructor can be written for example the following way
#include <functional>
//...
~List(){
while ( head ) delete std::exchange( head, head->next );
}
}

Related

Having trouble implementing a copy constructor for a doubly linked list

I am struggling to implement a copy constructor for a doubly linked list. The program compiles but I am running into an issue using the "push_back" function within the copy constructor to add the newly created nodes to the list. Below are the copy constructor and push_back functions in question.
List::List(const List& rhs) // Copy constructor
{
//this pointer is for the list that is being copied from
Node* rhsNodePtr;
//setting the new pointer to the first node of the old list
rhsNodePtr = rhs.first;
//looping until the end of the list
while(rhsNodePtr != nullptr){
//declaring new node to copy data into
Node* newNode = new Node("");
//copying node data from original list into new node
newNode->data = rhsNodePtr->data;
//adding new copied node to a new list
push_back(newNode->data);
//advancing the old list pointer location for the loop
rhsNodePtr = rhsNodePtr->next;
}
}
void List::push_back(string element)
{
Node* new_node = new Node(element);
if (last == nullptr) // List is empty
{
first = new_node;
last = new_node;
}
else
{
new_node->previous = last;
last->next = new_node;
last = new_node;
}
}
I apologize if I have omitted any relevant details. Please note that I am not just looking for a solution or correction but an explanation of why the push_back(); function is not working in my current implementation.
Edit: The while loop in the copy constructor gets stuck after the push_back function is called.
Edit: "First" and "last" are initialized in the List class declaration and both set to "nullptr" in the constructor.
Edit: After running through a debugger, I learned that there is an illegal memory access(segmentation fault) that occurs in the push_back function in the linelast->next = new_node;
You are not initializing last in the copy constructor. So the push_back gets called with garbage in it.
BTW I don't see the need for newNode and you don't free it. You can just push_back(rhsNodePtr->data); directly.
Your copy constructor is not initializing first and last (unless you are doing so in the class declaration, which you did not show), and it also leaks a Node on each loop iteration.
Try this instead:
List::List(const List& rhs)
: first(nullptr), last(nullptr) // <-- add this if needed
{
Node* rhsNodePtr = rhs.first;
while (rhsNodePtr) {
push_back(rhsNodePtr->data); // <-- no need to allocate a new Node for this call
rhsNodePtr = rhsNodePtr->next;
}
}
void List::push_back(string element)
{
Node* new_node = new Node(element);
new_node->previous = last;
new_node->next = nullptr; // <-- add this if needed
if (!first) first = new_node;
if (last) last->next = new_node;
last = new_node;
}

Dereferencing head of empty linked list for next node

I was trying to implement linked list in C++, when this idea struck my mind. With standard node definition as
class node {
public:
int data;
node *next;
};
I created an empty list node *head; then tried this
if(head->next == nullptr)
cout<<"Stores nullptr";
if(! head->next)
cout<<"Returns bool values";
But there is no output, so what is stored inside head->next ?
First of all, you should create some space/allocate memory for the node class in main.
Note that
node *head; is only a declaration not a definition. For further details have a look at What is the difference between a definition and a declaration?.
You allocate space for the object
Initialize its values, to be more elegant define a constructor method
node *head = new node;
head->next = nullptr;
head->data=0;
I would still consider this as a duplicate of Linked lists in C++
If you declare node *head;, head is an uninitialized pointer that contains a random address. Dereferencing it is Undefined Behavior?
You need to a) initialize head: node *head = nullptr;, and b) test for that condition: if (head == nullptr) { head = new node; node->head = nullptr; ...

c++ constructor seems to return pointer to the same object every time [duplicate]

This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Closed 5 years ago.
I have a simple implementation of a Linked list class, which has pointers to Node objects which I have also defined.
The function insertHead creates a new Node and inserts it at the head.
However, whenever I call the function, the constructor seems to return a pointer to the same object every time. (I checked that using GDB)
I am pasting snippets of the code here. Can someone please let me know if something seems off?
void LinkedList::insertHead(int val){
Node temp(val);
if(head == NULL){
head = tail = &temp;
} else {
temp.setNext(head);
head = &temp;
}
}
Class definitions:
class LinkedList{
Node *head;
Node *tail;
...
class Node{
int val;
Node *next;
...
Node::Node(int x){
val = x;
next = NULL;
}
You cant assign address of automatic storage variable and use it out of the body, becouse it got out of scope (undefined behaviour). You need to dynamically allocate space on heap for the node.
Node * temp = new Node(val);
if(head == NULL)
{
head = tail = temp;
} else {
temp.setNext(head);
head = temp;
}
And in destructor free all nodes.
You need to allocate your nodes on heap rather than stack. (I encourage you to read about those two). Also please use nullptr instead of NULL if supported ( > c++11)
void LinkedList::insertHead(int val){
Node* temp = new Node(val);
if(head == nullptr){
head = tail = temp;
} else {
temp->setNext(head);
head = temp;
}
}
This will also require you clean up the nodes properly using the delete to avoid memory leaks which will most probably require adding a custom destructor to your list class, something along those lines:
LinkedList::~LinkedList() {
Node* node = head;
while(node != nullptr) {
Node* toDel = node;
node = node->next;
delete toDel;
}
}

Deep Copy of a linked list that returns a Node pointer

I keep getting a segmentation fault on my deep copy of a linked list. I use this deep copy in my Copy Contructor and my assignment operator (operator=) and have come to the conclusion that it is this that is seg faulting.
bigint::Node* bigint::deepcopy(bigint::Node* target){
bigint::Node* current = target;
bigint::Node*cpy = new Node;
cpy->digit = current->digit;
Node* const hd = cpy;
current = current->next;
while(current != nullptr){
bigint::Node* tmp = new Node;
tmp->digit = current->digit;
cpy->next = tmp;
cpy = cpy->next;
current = current->next;
}
return hd;
}
My Node struct looks like:
private:
struct Node{
int digit;
Node* next;
};
Node* head;
static Node* deepcopy(Node* target);
My class is closed and all, just showing what is in private that is related to this function. Thanks in advance for any advice.
When you use your deepcopy function, you must make sure that the paramater target is not nullptr. So, you should check if (target == nullptr) at the beginning of your deepcopy function.
Also, after the while loop finished, you should set the tail of your new list to nullptr.
From the information you post, it seems you have use ->digit or ->next on a null pointer.
If you still get this error, you'd better provide a example code.

Program crashes after using "delete" on temp pointer, even if new and delete lines are the only ones left?

So I'm creating a doubly linked list class and use a temp node to insert new values and whatnot. So I have a Node struct:
template <typename T>
struct Node
{
// Data in this node
T mData;
// Link to previous node
Node* mPrev;
// Link to next node
Node* mNext;
};
and I have the following member variables in the actual List class:
// Pointer to the head node
Node<T>* mHead;
// Pointer to the tail node
Node<T>* mTail;
// Pointer to current node
Node<T>* mCurr;
// Number of nodes currently in the list
unsigned mSize;
All this is kosher, given to me by my professor.
However, whenever I create a temp pointer to insert a new value, using the delete keyword crashes the program with an error "First-chance exception at ... Access Violation reading location...". Here is an example of the function I'm writing:
void insert_front(const T& value)
{
Node<T>* temp = new Node<T>;
temp->mData = value;
temp->mPrev = nullptr;
temp->mNext = mHead;
if (mSize == 0)
{
mTail = temp;
mHead = temp;
}
else
{
mHead->mPrev = temp;
mHead = temp;
}
mSize++;
//delete temp;
}
Now aside from the obvious memory leak, this function works as it's supposed to. But when I add a delete ANYWHERE, the whole thing crashes. Even if I cut out EVERYTHING except for the new line and the delete line, everything crashes. The only other files in the program were created by my professor and have no errors. What am I doing wrong?
Were I betting man I'd wager that temp pointer is now an integral part of your list rather than a simple place holder.
if (mSize == 0)
{
mTail = temp;
mHead = temp;
}
else
{
mHead->mPrev = temp;
mHead = temp;
}
When you delete temp you are deleting whatever mTail and mHead or mHead->mPrev and mHead are pointing to. When you try to access this deleted data you get undefined behavior which is usually a crash.