I am trying to implement a linked list, and I am completely lost. I'm getting break points all over the place, specifically with the erase method. Whenever I alter the erase method, some error will inevitably spring up. I've got pointer errors, problems with the destructor that only occur when the erase method is called, and so on.
Here's what I have so far:
Header file:
#pragma once
class IntList {
private:
class IntNode {
public:
IntNode(int v, IntNode *pr, IntNode *nx);
~IntNode();
IntNode* previous;
IntNode* next;
class iterator {
public:
iterator(IntNode* t);
int& operator*();
iterator& operator++();
iterator& operator--();
bool operator!=(iterator other)const;
private:
IntNode* target;
};
private:
int value;
};
IntNode* head;
IntNode* tail;
int count;
public:
IntList();
~IntList();
void push_back(int v);
void pop_back();
int size() const { return count; }
typedef IntNode::iterator iterator;
iterator begin();
iterator end();
//unsigned int size() const;
void push_front(int value);
bool empty() const;
int& front();
int& back();
void clear();
iterator erase(iterator position);
};
Implementation:
#include "IntList.h"
#include <stdexcept>
IntList::IntList() : head{ nullptr }, tail{ nullptr }, count{ 0 }
{}
IntList::~IntList() {
while (head) {
head = head->next;
delete head;
}
}
void IntList::push_back(int v) {
tail = new IntNode{ v, tail, nullptr };
if (!head) { head = tail; }
count += 1;
}
void IntList::pop_back() {
tail = tail->previous;
delete tail->next;
count -= 1;
}
IntList::iterator IntList::begin()
{
return iterator{ head };
}
IntList::iterator IntList::end() {
return iterator{ nullptr };
}
void IntList::push_front(int value) {
head = new IntNode{ value, nullptr, head };
if (!tail) { tail = head; }
count += 1;
}
bool IntList::empty() const{
return (count==0);
}
int& IntList::front() {
return *begin();
}
int& IntList::back() {
return *begin();
}
void IntList::clear() {
head = nullptr;
tail = nullptr;
count = 0;
}
IntList::iterator IntList::erase(iterator position) {
int midpointL = 0;
for (iterator index = begin(); index != position; ++index) {
midpointL++;
}
if (midpointL == 0) {
head = head->next;
}
else if (midpointL == count) {
tail = tail->previous;
}
else {
// Move head to get a reference to the component that needs to be deleted
for (int i = 0; i < midpointL; i++) {
head = head->next;
}
// Change the previous and next pointers to point to each other
(head->previous)->next = (head->next);
(head->next)->previous = (head->previous);
for (int i = midpointL-1; i > 0; i++) {
head = head->previous;
}
}
count-=1;
return position;
}
IntList::IntNode::IntNode(int v, IntNode * pr, IntNode * nx)
: previous{ pr }, next{ nx }, value{ v }
{
if (previous) { previous->next = this; }
if (next) { next->previous = this; }
}
IntList::IntNode::~IntNode() {
if (previous) previous->next = next;
if (next) next->previous = previous;
}
IntList::IntNode::iterator::iterator(IntNode* t)
: target{ t }
{}
int& IntList::IntNode::iterator::operator*() {
if (!target) { throw std::runtime_error{ "Deferenced sentinel iterator." }; }
return target->value;
}
IntList::IntNode::iterator& IntList::IntNode::iterator::operator++()
{
if (target) { target = target->next; }
return *this;
}
IntList::IntNode::iterator& IntList::IntNode::iterator::operator--()
{
if (target) { target = target->previous; }
return *this;
}
bool IntList::IntNode::iterator::operator!=(iterator other)const
{
return (!(target == other.target));
}
Could anyone help point me in the right direction?
Thanks!
Let's make a kind of quick review here:
IntList::~IntList() {
while (head) {
head = head->next;
delete head;
}
}
you should do instead:
IntList::~IntList() {
while (head) {
IntNode* newHead = head->next;
delete head;
head = newHead;
}
}
as you are deleting the "next" object and then you are trying to get access to it in the next iteration.
void IntList::pop_back() {
tail = tail->previous;
delete tail->next;
count -= 1;
}
Here you are not checking if tail is null or if it is pointing to head..(what's the empty condition?), maybe count!=0? in case you may delete a not existing next-node
IntList::iterator IntList::end() {
return iterator{ nullptr };
}
..end is null? ebd should be your tail...
int& IntList::back() {
return *begin();
}
that's begin..not back.
void IntList::clear() {
head = nullptr;
tail = nullptr;
count = 0;
}
a clear should release all the objects in the list. You are generating garbage here (leaks).
I stopped here, sorry for that, it's just a coffee break. But you should look carefully at:
* null pointer usage
* delete your node list item when not needed
* pay attention to do not use invalid pointers (like head->previous->next I saw somewhere)
You have to review your code, bottom up. Hope that those first hints help you through your learning process.
Have fun,
Ste
Related
I am trying to write a playlist method for songs in c++, however, I keep running into frequent errors.
template <typename T>
struct cir_list_node
{
T* data;
cir_list_node *next, *prev;
//destructor
~cir_list_node() {
delete data;
}
};
template <typename T>
struct cir_list
{
public:
using node = cir_list_node<T>; // renaiming for local use
using node_ptr = node*;
private:
node_ptr head;
size_t n;
public:
// basic constructor and size function
cir_list(): n(0) // initiator list
{
head = new node(NULL,NULL,NULL); //dummy node
head->next = head; // circular list wraps around
head->prev = head;
}
cir_list(const cir_list& other): cir_list()
{
// insert in reverse order (okay because list is circular)
for(const auto& i : other)
insert(i);
}
cir_list(const std::initializer_list<T>& il): head(NULL), n(0)
{
//insert in reverse order
for(const auto& i : il)
insert(i);
}
~cir_list()
{
while(size())
{
erase(head->data);
}
}
size_t size() const
{
return n;
}
void insert(const T& value)
{
node_ptr newNode = new node(new T(value),NULL,NULL);
n++;
auto dummy = head->prev;
dummy->next = newNode;
newNode->prev = dummy;
if(head == dummy) {
dummy->prev = newNode;
newNode->next = dummy;
head = newNode;
return;
}
newNode->next = head;
head->prev = newNode;
head = newNode;
return;
}
void erase(const T& value)
{
auto cur = head, dummy = head->prev;
while (cur != dummy){
if(*(cur->data) == value){
cur->prev->next = cur->next;
cur->next->prev = cur->prev;
if(cur == head)
head = head->next;
delete cur;
n--;
return;
}
cur = cur->next;
}
}
struct cir_list_it
{
private:
node_ptr ptr;
public:
cir_list_it(node_ptr p) : ptr(p)
{}
T& operator*()
{
return *(ptr->data);
}
node_ptr get()
{
return ptr;
}
cir_list_it& operator++() // prefix
{
ptr = ptr->next;
return *this;
}
cir_list_it operator++(int) // postfix
{
cir_list_it it = *this;
++(*this);
}
cir_list_it& operator--() //prefix
{
ptr = ptr->prev;
return *this;
}
cir_list_it operator--(int) // postfix
{
cir_list_it it = *this;
--(*this);
return it;
}
friend bool operator == (const cir_list_it& it1, const cir_list_it& it2)
{
return it1.ptr == it2.ptr;
}
friend bool operator != (const cir_list_it& it1, const cir_list_it& it2)
{
return it1.ptr != it2.ptr;
}
};
cir_list_it begin()
{
return cir_list_it {head};
}
cir_list_it end()
{
return cir_list_it {head->prev};
}
cir_list_it end() const
{
return cir_list_it{head->prev};
}
};
struct playlist
{
cir_list<int> list;
void insert(int song)
{
list.insert(song);
}
void erase(int song)
{
list.erase(song);
}
void loopOnce()
{
for(auto& song : list){
std::cout << song << " ";
}
std::cout << std::endl;
}
};
int main()
{
playlist pl;
pl.insert(1);
pl.insert(2);
std::cout << "Playlist: ";
pl.loopOnce();
playlist pl2 = pl;
pl2.erase(2);
pl2.insert(3);
std::cout << "Second playlist";
pl2.loopOnce();
}
Errors
1 and 2:
3 and 4:
It seems there is a typo
struct cir_list_node
{
T* data;
cir_list_node *next, *prev;
//destructor
~cir_list_node() {
delete data;
}
};
You forgot to prefix this declaration with
template <typename T>
This template structure declaration declares an aggregate.
You can not initialized it with an expression inside parentheses like
head = new node(NULL,NULL,NULL);
Instead you need to write using braces
head = new node { NULL, NULL, NULL };
or as you are writing a C++ program then
head = new node { nullptr, nullptr, nullptr };
It seems there is a typo
struct cir_list_node
{
T* data;
cir_list_node *next, *prev;
//destructor
~cir_list_node() {
delete data;
}
};
I'm trying to get user input to insert element in the linked list. It works if I try to add at 1st or 2nd position. Even though list has more than 3 element, if I put 3 in it, it never works and returns nothing showing no syntax error. Is it wrong use with variable or loop. I'm super confused.
#include<stdlib.h>
#include<stdio.h>
struct Node
{
int data;
Node *next;
};
Node *head;
void insert(int data, int n)
{
Node* temp1 = new Node;
temp1->data = data;
temp1->next = NULL;
if(n == 1)
{
temp1->next = head;
head = temp1;
return;
}
else{
Node *temp2 = head;
for(int i = 0; i = n - 2; i++)
{
temp2 = temp2->next;
}
temp1->next = temp2->next;
temp2->next = temp1;
return;
}
}
void print()
{
Node *temp = head;
while(temp != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
}
int main()
{
head = NULL;
insert(3, 1);
insert(33, 1);
insert(384, 2);
insert(384, 1);
insert(432, 3);
insert(34, 4);
print();
}
The obvious mistakes have been already elaborated in the comment. Something additional.
If this is intended to be C++, then you should also use C++ language, especially classes.
Then from your design. Please do not mix up the "Node" with the "Linked List". A node is a part of a linked list. It is contained within the linked list. And it should not be exposed to the outside world.
I you want to read a little bit about needed functionality of a linked list, then you may check the CPP reference. For example here
And an example, from which you can take more ideas is listed below.
But first you need to read a book, this thing made out of real paper :-)
#include <iostream>
#include <iterator>
#include <initializer_list>
#include <algorithm>
// Very simple implementation of a forward list
template <class T>
class SinglyLinkedList {
// The node
struct Node {
T data{}; // Data. Would normally be a templated argument
Node* next{}; // And the pointer to the next node
Node(const T& i, Node* n = nullptr) : data(i), next(n) {}; // Simple constructor to set a value and next pointer
};
Node* head{}; // This is the start of the list
// It would be advisable to have a tail pointer. We use the more inefficient approach here
Node* getLast() const { Node* n{ head }; while (n and n->next) n = n->next; return n; }
public:
// Constructor / Destructor --------------------------------------------------------------------------------------------------------
~SinglyLinkedList() { clear(); }
// Default constuctor
SinglyLinkedList() {} // Default
// From an initialization list
SinglyLinkedList(const std::initializer_list<T>& il) { clear(); for (const T& i : il) push_back(i); } // From initializer list
// Copy constructor
SinglyLinkedList(const SinglyLinkedList& other) { clear(); for (const T& i : other) push_back(i); }
// Move constructor. Will steal the elements from the other
SinglyLinkedList(SinglyLinkedList&& other) noexcept { head = other.head; other.head = nullptr; }
// Assignment operator
SinglyLinkedList& operator = (const SinglyLinkedList& other) { clear(); for (const T& i : other) push_back(i); }
// Move assignment operator
SinglyLinkedList& operator = (SinglyLinkedList&& other) { head = other.head; other.head = nullptr; }
// Housekeeping --------------------------------------------------------------------------------------------------------------
void clear() { Node* tmp{ head }; while (tmp) { Node* toDelete{ tmp }; tmp = tmp->next; delete toDelete; } head = nullptr; }
int empty() const { return head == nullptr; }
int size() const { int k{}; Node* n{ head }; while (n) { ++k; n = n->next; } return k; }
// Modify content --------------------------------------------------------------------------------------------------------------
void push_front(const T& i) { Node* n = new Node(i); n->next = head; head = n; };
void push_back(const T& i) { Node* n = new Node(i); Node* l = getLast(); if (l) l->next = n; else head = n; }
void pop_front() { if (head) { Node* tmp = head->next; delete head; head = tmp; } }
void pop_back() { // This is a little bit more difficult in a singly linked list
if (head) {
Node* n{ head }, * previous{};
while (n and n->next) {
previous = n;
n = n->next;
}
delete n;
if (previous)
previous->next = nullptr;
else
head->next = nullptr;
}
}
// Access elements --------------------------------------------------------------------------------
T& front() const { return head ? head->data : 0; };
T back() const { Node* n = getLast(); return n ? n->data : 0; }
// Add iterator properties to class ---------------------------------------------------------------
struct iterator { // Local class for iterator
Node* iter{}; // Iterator is basically a pointer to the node
// Define alias names necessary for the iterator functionality
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = T;
using pointer = T*;
using reference = T&;
// Constructor
iterator() {}
iterator(Node* n) : iter(n) {}
// Dereferencing
reference operator *() const { return iter->data; }
pointer operator ->() const { return &iter->data; }
// Aithmetic operations
iterator& operator ++() { if (iter) iter = iter->next; return *this; }
iterator operator ++(int) { iterator temp{ *this }; ++* this; return temp; }
iterator operator +(const difference_type& n) const { iterator temp{ *this }; difference_type k{ n }; while (k--)++temp; return temp; }
iterator& operator +=(const difference_type& n) { difference_type k{ n }; while (k--)++* this; return *this; };
// Comparison
bool operator != (const iterator& other) const { return iter != other.iter; }
bool operator == (const iterator& other) const { return iter == other.iter; }
bool operator < (const iterator& other) const { return iter < other.iter; }
bool operator > (const iterator& other) const { return iter > other.iter; }
bool operator <= (const iterator& other) const { return iter <= other.iter; }
bool operator >= (const iterator& other) const { return iter >= other.iter; }
// Difference. Also complicated, because no random access
difference_type operator-(const iterator& other) const {
difference_type result{};
Node* n{ iter };
while (n and n != other.iter) {
++result;
n = n->next;
}
return result;
}
};
// Begin and end function to initialize an iterator
iterator begin() const { return iterator(head); }
iterator end() const { return iterator(); }
// Functions typcical for forward lists ----------------------------------------------------------------------
// Easy, becuase we can operate form the current iterator and do not need the "previous" element
iterator insertAfter(iterator& pos, const T& i) {
iterator result{};
if (pos.iter and pos.iter->next) {
Node* n = new Node(i, pos.iter->next);
pos.iter->next = n;
result = n;
}
return result;
}
iterator eraseAfter(iterator& pos) {
iterator result{};
if (pos.iter and pos.iter->next) {
Node* tmp = pos.iter->next->next;
delete pos.iter->next;
pos.iter->next = tmp;
result = pos.iter->next;
}
return result;
}
};
// Test/Driver Code
int main() {
// Example for initilizer list
SinglyLinkedList<int> sllbase{ 5,6,7,8,9,10,11,12,13,14,15 };
// Show move constructor
SinglyLinkedList<int> sll(std::move(sllbase));
// Add some values in the front
sll.push_front(4);
sll.push_front(3);
sll.push_front(2);
sll.push_front(1);
// Delete 1st element (Number 1)
sll.pop_front();
// Delete last element
sll.pop_back();
// Use a std::algorithm on our custom linked list. Works because we have an interator
SinglyLinkedList<int>::iterator iter = std::find(sll.begin(), sll.end(), 8);
// Now add an element after 8
iter = sll.insertAfter(iter, 88);
// End delete the 9
iter = sll.eraseAfter(iter);
// Use range based for loop. Works because, we have iterators
for (int i : sll)
std::cout << i << ' ';
return 0;
}
Your mistake is in this for loop
for(int i = 0; i = n - 2; i++)
There is assignment operator(=) instead of equal to operator(==), also logic is wrong.
This is how it should be
#include<cstdlib>
#include<cstdio>
struct Node
{
int data;
Node *next;
};
Node *head;
void insert(int data, int n)
{
Node* temp1 = new Node;
temp1->data = data;
temp1->next = NULL;
if(n == 1)
{
temp1->next = head;
head = temp1;
return;
}
else{
Node *temp2 = head;
for(int i = 1; i < n - 1; i++)
{
temp2 = temp2->next;
}
temp1->next = temp2->next;
temp2->next = temp1;
return;
}
}
void print()
{
Node *temp = head;
while(temp != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
}
int main()
{
head = nullptr;
insert(3, 1);
insert(33, 1);
insert(384, 2);
insert(384, 1);
insert(432, 3);
insert(34, 4);
print();
}
So I am attempting to create a Linked List that can store books for a imaginative library. Within the linked list, each node should contain the branch of library, the author's name, the book's title, and the number of copies of said book.
I'm having difficulty creating a linked list with multiple fields per node. How would I go about it so that each node can store 3 separate strings and an integer, and then finally, a pointer to the next node?
Here is my current code.
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <stdexcept>
using namespace std;
template<typename T>
class Node
{
public:
T element;
Node<T>* next;
Node()
{
next = nullptr;
}
Node(T element) // Constructor
{
this->element = element;
next = nullptr;
}
};
template<typename T>
class Iterator : public std::iterator<std::forward_iterator_tag, T>
{
public:
Iterator(Node<T>* p)
{
current = p;
}
Iterator operator++() // Prefix ++
{
current = current->next;
return *this;
}
Iterator operator++(int dummy) // Postfix ++
{
Iterator temp(current);
current = current->next;
return temp;
}
T& operator*()
{
return current->element;
}
bool operator==(const Iterator<T>& iterator)
{
return current == iterator.current;
}
bool operator!=(const Iterator<T>& iterator)
{
return current != iterator.current;
}
private:
Node<T>* current;
};
template<typename T>
class LinkedList
{
public:
LinkedList();
LinkedList(const LinkedList<T>& list);
virtual ~LinkedList();
void addFirst(T element);
void addLast(T element);
T getFirst() const;
T getLast() const;
T removeFirst() throw (runtime_error);
T removeLast();
void add(T element);
void add(int index, T element);
void clear();
bool contains(T element) const;
T get(int index) const;
int indexOf(T element) const;
bool isEmpty() const;
int lastIndexOf(T element) const;
void remove(T element);
int getSize() const;
T removeAt(int index);
T set(int index, T element);
Iterator<T> begin() const
{
return Iterator<T>(head);
}
Iterator<T> end() const
{
return Iterator<T>(tail->next);
}
private:
Node<T>* head;
Node<T>* tail;
int size;
};
template<typename T>
LinkedList<T>::LinkedList()
{
head = tail = nullptr;
size = 0;
}
template<typename T>
LinkedList<T>::LinkedList(const LinkedList<T>& list)
{
head = tail = nullptr;
size = 0;
Node<T>* current = list.head;
while (current != nullptr)
{
this->add(current->element);
current = current->next;
}
}
template<typename T>
LinkedList<T>::~LinkedList()
{
clear();
}
template<typename T>
void LinkedList<T>::addFirst(T element)
{
Node<T>* newNode = new Node<T>(element);
newNode->next = head;
head = newNode;
size++;
if (tail == nullptr)
tail = head;
}
template<typename T>
void LinkedList<T>::addLast(T element)
{
if (tail == nullptr)
{
head = tail = new Node<T>(element);
}
else
{
tail->next = new Node<T>(element);
tail = tail->next;
}
size++;
}
template<typename T>
T LinkedList<T>::getFirst() const
{
if (size == 0)
throw runtime_error("Index out of range");
else
return head->element;
}
template<typename T>
T LinkedList<T>::getLast() const
{
if (size == 0)
throw runtime_error("Index out of range");
else
return tail->element;
}
template<typename T>
T LinkedList<T>::removeFirst() throw (runtime_error)
{
if (size == 0)
throw runtime_error("No elements in the list");
else
{
Node<T>* temp = head;
head = head->next;
if (head == nullptr) tail = nullptr;
size--;
T element = temp->element;
delete temp;
return element;
}
}
template<typename T>
T LinkedList<T>::removeLast()
{
if (size == 0)
throw runtime_error("No elements in the list");
else if (size == 1)
{
Node<T>* temp = head;
head = tail = nullptr;
size = 0;
T element = temp->element;
delete temp;
return element;
}
else
{
Node<T>* current = head;
for (int i = 0; i < size - 2; i++)
current = current->next;
Node<T>* temp = tail;
tail = current;
tail->next = nullptr;
size--;
T element = temp->element;
delete temp;
return element;
}
}
template<typename T>
void LinkedList<T>::add(T element)
{
addLast(element);
}
template<typename T>
void LinkedList<T>::add(int index, T element)
{
if (index == 0)
addFirst(element);
else if (index >= size)
addLast(element);
else
{
Node<T>* current = head;
for (int i = 1; i < index; i++)
current = current->next;
Node<T>* temp = current->next;
current->next = new Node<T>(element);
(current->next)->next = temp;
size++;
}
}
template<typename T>
void LinkedList<T>::clear()
{
while (head != nullptr)
{
Node<T>* temp = head;
head = head->next;
delete temp;
}
tail = nullptr;
size = 0;
}
template<typename T>
T LinkedList<T>::get(int index) const
{
if (index < 0 || index > size - 1)
throw runtime_error("Index out of range");
Node<T>* current = head;
for (int i = 0; i < index; i++)
current = current->next;
return current->element;
}
template<typename T>
int LinkedList<T>::indexOf(T element) const
{
// Implement it in this exercise
Node<T>* current = head;
for (int i = 0; i < size; i++)
{
if (current->element == element)
return i;
current = current->next;
}
return -1;
}
template<typename T>
bool LinkedList<T>::isEmpty() const
{
return head == nullptr;
}
template<typename T>
int LinkedList<T>::getSize() const
{
return size;
}
template<typename T>
T LinkedList<T>::removeAt(int index)
{
if (index < 0 || index >= size)
throw runtime_error("Index out of range");
else if (index == 0)
return removeFirst();
else if (index == size - 1)
return removeLast();
else
{
Node<T>* previous = head;
for (int i = 1; i < index; i++)
{
previous = previous->next;
}
Node<T>* current = previous->next;
previous->next = current->next;
size--;
T element = current->element;
delete current;
return element;
}
}
// The functions remove(T element), lastIndexOf(T element),
// contains(T element), and set(int index, T element) are
// left as an exercise
#endif
Given a struct, such as
struct Book
{
std::string branch;
std::string author;
std::string title;
int copies;
};
A LinkedList<Book> would have all the data elements you want in each Node.
so I was trying to build this project on deque using the doubly linked list. but when I build it. it says build but gives threads and doesn't give the output as required.
I have re-implemented the major problem(copy constructor) and all the functions again and again but then it still gives me new threads every time.
this is the header file.
#pragma once
#include <stdexcept>
using namespace std;
class Node
{
public:
int data;
Node* next;
Node* previous;
Node();
Node(const int &x);
};
class Deque
{
public:
Deque();
Deque(const Deque &d);
Deque &operator= (const Deque &d);
~Deque();
void insertFront(const int &x);
void insertBack(const int &x);
int removeFront();
int removeBack();
int peekFront();
int peekBack();
bool empty() const;
int size()const;
friend ostream& operator << (ostream &out, const Deque &d);
private:
Node* front;
Node* rear;
};
this will be the .cpp (implementation file.)
//
// Deque_cmpt225.cpp
// Deque_cmpt225
//
// Created by Aryan Arora on 2017-10-09.
// Copyright © 2017 Aryan Arora. All rights reserved.
//
#include "Deque_cmpt225.h"
#include <iostream>
#include <stdexcept>
using namespace std;
Node:: Node()
{
previous = nullptr;
next = nullptr;
data = 0;
}
Node:: Node(const int &x)
{
Node();
data = x;
}
Deque:: Deque() //Empty Deque.
{
front = nullptr;
rear = nullptr;
}
Deque:: ~Deque()
{
if (this->empty())
return;
else{
Node* temp;
while (this->front->next != nullptr){
temp = this->front;
this->front = this->front->next;
delete temp;
}
temp = this->front;
this->front = nullptr;
this->rear = nullptr;
delete temp;
}
}
Deque:: Deque (const Deque &d) //Copy Constructor
{
if (d.empty()) //Deque is empty.
{
return;
}
Node* temp = d.front;
int x;
if (temp->next == nullptr) //Deque of just one node
{
x = temp->data;
Node *n1 = new Node (x);
n1->next = nullptr;
n1->previous = nullptr;
this->front = n1;
this->rear = n1;
}
else //Deque has more than one node
{
while (temp!= nullptr)
{
this->insertBack(temp->data);
temp = temp -> next;
}
}
}
Deque& Deque:: operator=(const Deque &d) //============================check again
{
if (this == &d)
return *this;
else
{
this->~Deque(); //DELETING THE DEQUE
Node* temp = d.front; //COPYING EACH NODE
while (temp != NULL)
{
this->insertBack(temp->data); //INSERTING AT THE BACK
temp = temp->next; //POINTING TEMP TO NEXT NODE
}
}
return *this;
}
void Deque:: insertFront(const int &x)
{
Node* temp = new Node(x);
temp->next = nullptr;
temp->previous = nullptr;
if (empty())
{
this->front = temp;
this->rear = temp;
}
else
{
temp->next = this->front;
temp->previous = nullptr;
this->front->previous = temp;
this->front = temp;
}
}
void Deque:: insertBack(const int &x)
{
Node* temp = new Node(x);
temp->next = nullptr;
temp->previous = nullptr;
if (empty())
{
this->front = temp;
this->rear = temp;
}
else
{
temp->next = nullptr;
temp->previous = this->rear;
this->rear->next = temp;
this->rear = temp;
}
}
int Deque:: removeFront()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else{
Node* temp;
temp = this->front;
int x = temp->data;
if ( this->front->next != nullptr )
{
this->front = this->front->next;
this->front->previous = nullptr;
}
else
{
this->front = nullptr;
this->rear = nullptr;
}
delete temp;
return x;
}
}
int Deque:: removeBack()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else{
Node* temp = this->rear;
int x = temp->data;
if ( this->rear->previous != nullptr )
{
this->rear = this->rear->previous;
this->rear->next = nullptr;
}
else
{
this->rear = nullptr;
this->front = nullptr;
}
delete temp;
return x;
}
}
int Deque:: peekFront()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else
{
return this->front->data;
}
}
int Deque:: peekBack()
{
if (empty()) //=================runtime error
{
throw std::runtime_error("The que is empty.");
}
else
{
return this->rear->data;
}
}
bool Deque:: empty() const
{
if (this->front == nullptr && this->rear == nullptr)
return true;
else
return false;
}
int Deque:: size() const
{
Node* temp = this->front;
int count = 0;
while (temp != nullptr)
{
count++;
temp = temp->next;
}
return count;
}
ostream& operator << (ostream &out, const Deque &d)
{
Node* temp = d.front;
out << "NULL -> ";
while (temp != nullptr)
{
out << temp->data << " <-> ";
temp= temp->next;
}
out << "<- NULL" << endl;
return out;
}
thanks in advance.
Your code has many problems..
Your Node constructor doesn't delegate properly..
Node::Node()
{
previous = nullptr;
next = nullptr;
data = 0;
}
Node::Node(const int &x)
{
Node(); //Creates a temporary node that gets destroyed immediately..
data = x;
}
It's much simpler if you change it to:
Node::Node() : Node(0) //Delegating constructor.
{
}
Node::Node(const int &x) : previous(nullptr), next(nullptr), data(x)
{
}
This point isn't really a problem, but worth mentioning.. You keep setting the Node pointers to nullptr right after construction. This is not necessary because your constructor already does that..
Node* temp = new Node(x);
temp->next = nullptr; //Not needed anymore with the above fixes.
temp->previous = nullptr; //Not needed anymore with the above fixes.
You never initialize your variables in the copy constructor..
In your constructor, you have (I changed it, but it has the same meaning):
Deque::Deque() : front(nullptr), rear(nullptr)
{
}
But in your copy constructor, you have:
Deque::Deque(const Deque &d)
{
//Other code here.. You never initialized front and rear to nullptr..
}
You never set front and rear to nullptr so empty() returns false since they are a "random" uninitialized value.. Then in insertBack you go on to access this and boom.. Access Violation.
To fix it, you do:
Deque::Deque(const Deque &d) : front(nullptr), rear(nullptr)
{
//Other code here..
}
Next issue is that your copy assignment operator is calling the destructor!
Deque& Deque::operator=(const Deque &d)
{
if (this == &d)
return *this;
else
{
this->~Deque() //YOU CANNOT DO THIS.. Create a private member function for cleaning up.. Then call that function in your destructor and call that function here.. You cannot invoke the destructor like this.
}
//....
}
For academic purposes, I'm trying to develop a little "textual adventure game". I have to implement all data structures by my own. Now, I have some problems with the implementation of a generic (template) LinkedList.
In the specific, this data structure works with everything (primitive data types and custom objects) BUT strings! (standard library strings).
When I try to add strings to a list, the application crashes with the following error (in console):
"terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_constructor null not valid"
The list is implemented as a "double linked list" using the head-node as first-last node
Here the code ("Abstract" List interface):
#ifndef LIST_H_
#define LIST_H_
template <class T>
class List
{
public:
virtual ~List() {}
virtual T get(int position) = 0;
virtual List* add(T item) = 0;
virtual List* insert(T item, int position) = 0;
virtual List* remove(int position) = 0;
virtual int size() const = 0;
virtual bool isEmpty() const = 0;
protected:
private:
};
#endif /* LIST_H_ */
This is the LinkedList implementation (the "node" class):
#include "List.h"
#include <stdlib.h>
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
template <class T>
class ListNode
{
public:
ListNode(T item)
{
mItem = item;
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item;
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem;
}
T getItem()
{
return mItem;
}
ListNode<T>* getNext()
{
return mNext;
}
ListNode<T>* getPrev()
{
return mPrev;
}
void setItem(T item)
{
mItem = item;
}
void setNext(ListNode<T>* next)
{
mNext = next;
}
void setPrev(ListNode<T>* prev)
{
mPrev = prev;
}
protected:
private:
T mItem;
ListNode<T> *mNext, *mPrev;
};
The LinkedList class:
template <class K>
class LinkedList : public List<K>
{
public:
LinkedList()
{
mSize = 0;
mFirstNode = NULL;
}
~LinkedList()
{
// implementazione distruttore tramite ciclo sui nodi
}
K get(int position)
{
K item = NULL;
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL) item = targetNode->getItem();
return item;
}
List<K>* add(K item)
{
if (mFirstNode == NULL)
{
mFirstNode = new ListNode<K>(item);
mFirstNode->setNext(mFirstNode);
mFirstNode->setPrev(mFirstNode);
}
else
{
ListNode<K>* newNode = new ListNode<K>(item, mFirstNode, mFirstNode->getPrev());
mFirstNode->getPrev()->setNext(newNode);
mFirstNode->setPrev(newNode);
}
mSize++;
return this;
}
List<K>* insert(K item, int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
ListNode<K>* newNode = new ListNode<K>(targetNode->getItem(), targetNode->getNext(), targetNode);
targetNode->setItem(item);
targetNode->setNext(newNode);
mSize++;
}
return this;
}
List<K>* remove(int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
targetNode->setItem(targetNode->getNext()->getItem());
targetNode->setNext(targetNode->getNext()->getNext());
//delete targetNode->getNext();
mSize--;
}
return this;
}
int size() const
{
return mSize;
}
bool isEmpty() const
{
return (mFirstNode == NULL) ? true : false;
}
protected:
ListNode<K>* getNodeAtPosition(int position)
{
ListNode<K>* current = NULL;
if (mFirstNode != NULL && position < mSize)
{
current = mFirstNode;
for (int i = 0; i < position; i++)
{
current = current->getNext();
}
}
return current;
}
private:
int mSize;
ListNode<K>* mFirstNode;
};
#endif /* LINKEDLIST_H_ */
Suggestions?
Part of your problem is here:
ListNode(T item)
{
mItem = item; // for a std::string, this will be a class member, non-pointer
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item; // same here
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem; // you are attempting to delete an item you never created
}
You should either change your constructors to create a T* object on the heap (which will then be deleted in your destructor), or remove the delete line from your destructor.
This problem will be evident with far more than just std::string, by the way.
Somewhere in your program you are doing this:
std::string s(nullptr);
Calling std::string's constructor with a null pointer is causing it to throw a std::logic_error exception.
From the standard:
§ 21.4.2
basic_string(const charT* s, size_type n, const Allocator& a = Allocator());
Requires: s shall not be a null pointer and n < npos.
It seems it's not possible to pass std::string as template argument...
Strings as Template Arguments
Now I use an "old" - char const* - to achieve the expected result, even if I have to implement my personal "utils" methods to work with those pointers now...