converting queue to linked list when using operator== c++ - c++

I have a queue and a linked list. I am trying to call the operator== function in the linked list through the queue function. The assignment is asking me to compare 2 queues and see if they are the same. I have included the functions from each file that are giving me trouble.
The error message I'm getting is "C2664 'bool List::operator ==(List &)': cannot convert argument 1 from 'const Q' to 'List &'"
queue.h
class Q
{
public:
Q();
Q(const Q &queue);
~Q();
bool operator==(const Q &queue);
private:
List queue;
};
queue.cpp
Q::Q(){}//constuctor
Q::Q(const Q &queue){}//copy constructor
Q::~Q(){}//deconstuctor
bool Q::operator==(const Q &queue1)//this is where the problem is
{
return queue.operator==(queue1);
}
list.h
class List
{
private:
struct Node
{
int data;
Node* next;
Node() : next(NULL) {} //define our own default constructor
Node(int data) : next(NULL), data(data) {}
};
typedef struct Node* NodeRef;
NodeRef head;
NodeRef tail;
NodeRef iterator;
NodeRef current1;
int size;
public:
List();
~List();
List(const List &list);
bool operator==(List &queue);// this is where i have the problem
};
list.cpp
bool List::operator==(List& queue)
{
if (size != queue.size)
return false;
iterator = head;
NodeRef temp = queue.head;
while (iterator != NULL)
{
if (iterator->data != temp->data)
return false;
temp = temp->next;
iterator = iterator->next;
}
return true;
}
main.cpp
Q k,qw;
if (k == qw)
cout << "Lists are equal!\n";
else
cout << "Lists are unequal!\n";
Please help.

You need to compare like for like, in this case a Q only has a queue element (which is actually a List), so when comparing objects of type Q, you need to compare their queue elements.
As you already have an operator == for the List class, so this is straightforward.
bool Q::operator==(const Q &queue1)
{
return queue == queue1.queue;
}

Right, there are a couple of issues here:
return queue.operator==(queue1);
Surely you wanted to use return queue.operator==(queue1.queue); or the shorter return queue == queue1.queue; to compare the internal Queue::List, otherwise, what's the point?
bool operator==(List &queue);
This declaration should become bool operator==(const List &queue); you basically want to use the const whenever you're not changing anything since it allows you to pass both variables and constants to functions. If you don't do it in this case, your code will break since in point 1 you are passing a const.
bool List::operator==(List& queue)
This should become bool List::operator==(const List& queue) since definition should match declaration

Related

How did this loophole around const member function worked?

In the below code we try to multiply each element's data in the list by 2 and assign it. But the apply function is a const function therefore should not be able to change the values of member fields. Output for the fifth line in main is
6
4
2
2
4
So code below succeeds in changing the values as intended and I can't figure out why.
#include <iostream>
#include <list>
#include <string>
using std::ostream;
using std::cout;
using std::endl;
template<class E> class MyList {
class Node {
friend class MyList<E>;
E data;
Node* next = nullptr;
}; // end of class Node
Node* head = new Node;
Node* tail = head;
MyList(const MyList&) = default;
public:
MyList() = default;
MyList& operator=(const MyList&) = delete;
void push_front(const E& data) {
Node* node = new Node;
node->data = data;
node->next = head->next;
head->next = node;
if(head->next == nullptr) tail = node;
}
void push_back(const E& data) {
if(head->next == nullptr) {
push_front(data); return;
}
MyList temp(*this);
temp.head = temp.head->next;
temp.push_back(data);
temp.head = nullptr;
}
~MyList() {
Node *node = head, *next;
while(node != nullptr) {
next = node->next;
delete node;
node = next;
}
}
template<class Function>
void apply (Function f) const {
Node* node = head->next;
while(node != nullptr) {
f(node->data);
node = node->next;
}
}
};
int main() {
MyList<int> m1;
m1.push_back(3);
for(int i = 1; i <= 2; ++i) m1.push_front(i);
for(int i = 1; i <= 2; ++i) m1.push_back(i);
m1.apply(
[](auto& val){ val *= 2;}
);
m1.apply(
[](const auto& val){cout << val << endl;}
);
return 0;
}
The key is logical vs bitwise constness. The head data member is a non-const pointer to non-const Node: the const correctness of the apply member function is bitwise constness:
you cannot change what the head data member (pointer) points to from a const-qualified member function.
You can, however, mutate the Node object that it points to.
Because it is not the same, the pointer you store in your const struct as a member, than the data pointed by that pointer, which still is of type Node* (non const).
Just for the sake of showing, try to set all the pointers to NULL:
while(node != nullptr) {
f(node); // Pass the Node*, instead of the reference to the value
node = node->next;
}
The above code will not compile, as you will be passing a Node* const& to your lambda, which will be a const reference and will not be possible to set it to NULL.
The const in the functions declarations is not transitive. The pointed memory accessed through some pointer member is not affected by that. It will still have the same type as that of the declared pointer member, in this case Node*.
This is called (as stated in the other answer) logical constness, and is ensured by the function const signature.
While you are trying to achieve bitwise constness, which is not achieved with the signature, but with the type declaration.
And about types, inside the const function the type of the pointer would become Node* const, meaning a constant pointer (logical constness, cannot change where it points), while the type of the data pointed is Node* (it can be changed, bitwise constness)

C++ linked list Segmentation fault and valgrind errors

i need to code a linked list for university in c++, mostly to practice coding iterators.
I tested it with some basic cases and it works but after i pass it in valgrind and the test server for the program i get a list of different errors. Maybe somebody can help me not to despair.
(At the end i will append the error list)
template <typename T = float>
class ForwardList
{
struct Node
{
/// Constructs a Node from a data value and a link to the next element.
Node(const T &data, Node *next) : data{data}, next{next} {}
/// A Node owns all nodes after it, so it deletes them on destruction
~Node() { delete next; }
//Performs a deep copy of the Node and all Nodes after it. Bad practice but we got it like that
Node *clone() const
{
if (next == nullptr)
{
return new Node{data, nullptr};
}
else
{
return new Node{data, next->clone()};
}
}
T data;
Node *next;
};
public:
ForwardList() : head(nullptr) {}
/// Copy constructor performs a deep copy of the other list's Nodes
ForwardList(const ForwardList &other)
{
head = other.head->clone();
}
/// Destructor makes sure that all Nodes are correctly destroyed
~ForwardList()
{
while (head->next != nullptr)
{
Node *tmp = head;
head = head->next;
delete tmp;
}
delete head;
}
/// Copy assignment operator uses the copy-and-swap idiom to make a safe
/// assignment
ForwardList &operator=(ForwardList other)
{
swap(*this, other);
return *this;
}
/// Add an element to the front of the list.
void push_front(const T &value)
{
std::cout << "Num: " << numberOfNodes << std::endl;
Node *item = new Node(value, nullptr);
if (head==nullptr)
{
head = item;
}else
{
item->next=head;
head = item;
}
numberOfNodes++;
}
/// Remove the first element of the list. Calling this function on an empty
/// list is undefined behavior. When implementing this function, be careful
/// to delete the one and only the one element that is removed.
void pop_front()
{
Node *item;
item = head->next;
delete head;
head = item;
numberOfNodes--;
}
/// Get a reference to the first element of the list
/// (const and non-const version)
T &front()
{
return head->data;
}
const T &front() const
{
return head->data;
}
/// Return true is the list is empty
bool empty() const
{
return numberOfNodes == 0 ? true : false;
}
std::size_t size() const
{
return numberOfNodes;
}
friend void swap(ForwardList &l, ForwardList &r)
{
Node *tmp = l.head;
l.head = r.head;
r.head = tmp;
}
private:
Node *head;
size_t numberOfNodes = 0;
};
And now the fun part (i will put it on pastebin because its pretty long):
https://pastebin.com/4JAKkJtP
Your issue is that ~Node tries to delete its next, and you also try to walk the list in ~ForwardList. By deleting ~Node(), you let ForwardList handle cleanup and everything works.
The clue here is that valgrind reported use after free, meaning something was deleting a pointer twice. That was a clue to look at everything that deletes a Node* (or really, delete in general).

Recursive length function implementation in a linked-list

I am implementing a linked-list, and one of the function asks for the number of nodes in the linked list. However, as the requirement says it needs to be done recursively.
Here is my implementation so far.
class LList {
public:
bool isEmpty() const;
void cons(int x);
int length() const;
private:
struct Node {
int item;
Node* next;
};
Node* head;
}
bool LList::isEmpty() const{
if(head == nullptr)
return true;
else
return false;
}
void LList::cons(int x){
Node* temp = new Node;
temp->item = x;
temp->next = head;
head = temp;
}
I can only do this iteratively, but couldn't make the recursion work.
int LList::length(Node* head) const{
Node* temp = head;
if (temp == nullptr) {
return 0;
}
return 1 + length(temp->next);
}
int LList::length() const {
return length(head);
}
I tried to use a helper function to do the job, but it's saying declaration is incompatible with int LList::length() const
Can anyone help me with this problem?
You are recursing the wrong place: You only have a single LList, so there is nothing to recurse on there. What you want to do instead is to recurse on the Node objects.
Keep your int LList::length() const function, but all it has to do is check if head is nullptr and then call the new recursive function that you are going to make: int LList::Node::length() const. This one then recurses through the next pointers of your Node objects and counts them.

Iterator in my implementation of std::list does not work

I'm trying to write a template of list like std::list one.
This is my code in List.h:
#include <memory>
#include <cassert>
#include <iterator>
template<typename T, class Node>
class iterator : public std::iterator<std::bidirectional_iterator_tag, Node *, Node &> {
Node *underlying;
public:
explicit iterator(Node *n) : underlying(n) { };
iterator() : underlying(nullptr) { };
iterator &operator++() { //preinc
assert(underlying != nullptr && "Out-of-bounds iterator increment!");
underlying = underlying->next;
return *this;
}
iterator operator++(int) { //postinc
assert(underlying != nullptr && "Out-of-bounds iterator increment!");
iterator temp(*this);
++(*this);
return temp;
}
iterator &operator--() { //predec
assert(underlying != nullptr && "Out-of-bounds iterator decrement!");
underlying = underlying->previous;
return *this;
}
iterator operator--(int) { //postdec
assert(underlying != nullptr && "Out-of-bounds iterator decrement!");
iterator temp(*this);
--(*this);
return temp;
}
bool operator==(const iterator &rhs) {
return underlying == rhs.underlying;
}
bool operator!=(const iterator &rhs) {
return underlying != rhs.underlying;
}
T &operator*() {
return underlying->data;
}
};
template<typename T>
class List {
class Node {
public:
T data;
Node *previous;
Node *next; //is that T needed?
Node(T &d) : data(d) { };
};
private:
Node *head; //first element
Node *tail;
void create() { head = tail = NULL; }
void create(const List &rhs) {
iterator this_iter = head;
iterator rhs_iter = rhs.head;
while (rhs_iter != NULL) {
this_iter->data = (rhs_iter++)->data;
++this_iter;
}
};
public:
typedef T *iterator;
typedef const T *const_iterator;
typedef size_t size_type;
typedef T value_type;
List() { create(); };
List &operator=(const List &rhs) {
if (&rhs != this) {
create(rhs);
}
return *this;
};
List(const List &rhs) { create(rhs); };
~List() { while(head) remove(head); };
T *begin() { return head; };
T *end() { return tail; };
T front() { return head->data; };
T back() { return tail->data; };
bool empty() { return head == NULL; }
size_type size() {
size_t i = 0;
Node *node = head;
while (node) {
node = node->next;
i++;
}
return i;
};
T &operator[](size_type i) {
if (i < size() && i >= 0) {
Node *temp = head;
while (i > 0) {
temp = temp->next;
i--;
}
return temp->data;
}
throw std::out_of_range("Index out of range");
};
// const T &operator[](size_type i) const; //how to implement and do not duplicate code?
Node *push_back(value_type data) {
Node *n = new Node(data);
if (head == NULL) {
head = tail = n;
} else {
n->previous = tail;
tail->next = n;
tail = n;
}
return n;
};
Node *push_front(value_type data) {
Node *n = new Node(data);
if (head == NULL) {
head = tail = n;
} else {
n->next = head;
head->previous = n;
head = n;
}
return n;
};
void pop_front() {
remove(head);
};
void pop_back() {
remove(tail);
};
void remove(Node *n){
if(n == NULL) return;
if(n == head){
head = n->next;
head->previous =NULL;
}
else if(n == tail){
tail = n->previous;
tail->next = NULL;
}
else{
n->previous->next = n->next;
n->next->previous = n->previous;
}
delete n;
}
};
And this is main.cpp
#include <iostream>
#include "List.h"
int main(){
List<int> l;
l.push_back(1);
l.push_back(2);
l.push_back(3);
l.pop_back();
l.pop_front();
l.push_back(4);
l.push_back(5);
for (size_t i = 0; i < l.size(); i++)
std::cout << l[i] << "\n";
std::cout<<"Front "<<l.front();
std::cout<<"Back "<<l.back();
}
Actually push_back/front , pop_back/front and []operator work fine. But I get "Process finished with exit code 139"
error when I try use front() or back(). And I know that this iterator of list template does not work but I do know how to combine it up. Could anyone hint or help?
EDIT:
Ok, I have fixed the problem with removing and front(), tail() methods. But still the iterator thing doesnt work.
For example this code:
for(List<int>::iterator it = l.begin(); it!=l.end(); it++){
std::cout << it << "\n";
}
Gives me erros:
error: cannot convert ‘List<int>::Node*’ to ‘List<int>::iterator {aka int*}’ in initialization
for(List<int>::iterator it = l.begin(); it!=l.end(); it++){
^
error: comparison between distinct pointer types ‘List<int>::iterator {aka int*}’ and ‘List<int>::Node*’ lacks a cast [-fpermissive]
for(List<int>::iterator it = l.begin(); it!=l.end(); it++){
^
I know that te problem is with wraping the node with iterator template and that I have got "typename T *iterator".
Your begin and end methods return Node*, not your iterator type. And you made the iterator constructor that accepts Node* as an argument explicit; you told the compiler that implicit conversion from List<int>::Node* to List<int>::iterator is disallowed.
You must do one of:
Remove explicit from explicit iterator(Node *n) : underlying(n) { }; (though this risks implicit conversions in scenarios you don't want)
Change begin and end to return iterator(head) and iterator(tail) (performing explicit conversion to iterator) rather than head and tail (and change the return type of begin and end to iterator, which you should really do regardless)
You have some other issues too:
You should not have done typedef T* iterator in List; that hid the definition of your iterator class, so List never used it. Fixing that (and adding the necessary templating to your uses of iterator) makes it compile
The inheritance definition of iterator should be template<typename T, class Node> class iterator : public std::iterator<std::bidirectional_iterator_tag, T> not template<typename T, class Node> class iterator : public std::iterator<std::bidirectional_iterator_tag, Node *, Node &>; the latter is declaring the value from dereferencing should be Node * (when you want it to be T, the value in each Node)
end should return iterator<T, Node>(nullptr) not iterator(tail); otherwise, you stop before printing the value of tail, when you want to print tail before you terminate the loop.
Once all that is done, you should compile and get the results you expect. The code still has problems, e.g.
It's not const correct and offers no const versions of various accessors, which can prevent optimizations; you may end up recomputing size on every loop if the compiler can't figure out that the loop is actually non-mutating
The copy constructor/assignment utility function create doesn't work (you'd want to iterate over rhs and push_back repeatedly, you can't use an iterator to push on new values
The lack of const accessors means that utility function can't be made to work; it would need a const iterator type to iterate rhs with a guarantee that it would not violate the const List& requirement, but you only defined mutating iterator functions
But that it performance optimizations and correctness in code you're not exercising; you can fix that once you're satisfied with the new code.
I've your code (though the fix to copy construction/assignment is an egregious hack using const_cast to brute force around the lack of const safe iteration); I also added a couple tests to show that copy construction and assignment work. Take a look.
The problem (a problem?) is in remove(): you don't check if head is NULL (head case), if tail is NULL (tail case) and if n->previous and n->next are null (generic case)
I suggest this remove()
void remove(Node *n){
if(n == NULL) return;
if(n == head){
head = n->next;
if ( head )
head->previous =NULL;
}
else if(n == tail){
tail = n->previous;
if ( tail )
tail->next = NULL;
}
else{
if ( n->previous )
n->previous->next = n->next;
if ( n->next )
n->next->previous = n->previous;
}
delete n;
}

Overloading operators for adding two doubly linked lists

I need help with overloading '+' operator for adding together two doubly linked lists. I cannot compile my program due to getting "no match for operator=..." error. I have overloaded '=' operator already but struggle to print the result of the addition to std output. I have also overloaded the << operator. Been trying to figure out what is wrong for hours with no success. Any hints how to tackle this problem and/or solutions to it are very welcome. It is assignment for my OOP class.
Thanks in advance!
EDIT: The basic idea behind the code is to replicate set. Overloaded operators '+' should work as an union and '*' as intersection. I struggle to get the union properly printed to std output. '+=' seems to work fine. '<<' works good as well, but only when it comes to printing out single list.
EDIT:
Errors produced by compiler (g++, output from code::blocks, I have removed compiler notes):
llist3.cpp|149|error: no match for ‘operator=’ (operand types are ‘LList’ and ‘LList’)|
llist3.cpp|106|note: no known conversion for argument 1 from ‘LList’ to ‘LList&’|
llist3.cpp|151|error: no match for ‘operator=’ (operand types are ‘LList’ and ‘LList’)|
llist3.cpp|106|note: no known conversion for argument 1 from ‘LList’ to ‘LList&’|
llist3.cpp|152|error: no match for ‘operator<<’ (operand types are ‘std::ostream {aka std::basic_ostream<char>}’ and ‘LList’)|
#include<iostream>
using namespace std;
class LList {
public:
struct Node {
int elem;
Node* succ;
Node* prev;
Node() : succ(0), prev(0), elem(0) {}
};
LList();
LList(LList& list);
~LList();
Node* next();
Node* begin() { curr = head; }
int getElem() { return curr->elem; }
void addElem(int elem);
LList operator+(LList& set);
LList operator+(int elem);
LList& operator+=(LList& set);
LList& operator+=(int elem);
LList& operator=(LList& list);
friend ostream& operator<<(ostream& os, LList& obj);
private:
Node* curr;
Node* head;
Node* tail;
int size;
void pushFront(Node* n);
void pushInside(Node* n);
void pushBack(Node* n);
};
LList::LList() : head(0), tail(0), size(0), curr(0) {}
LList::LList(LList& list) : size(0), curr(0), head(0), tail(0) {
list.curr = list.head;
while(list.curr) {
addElem(list.getElem());
list.next();
}
}
LList::Node* LList::next() {
if (curr)
return (curr = curr->succ);
else
return 0;
}
void LList::addElem(int elem) {
Node* n = new Node;
n->elem = elem;
if (curr) {
if (curr == head && elem < curr->elem) {
pushFront(n);
}
else if (elem > curr->elem) {
curr = curr->succ;
addElem(elem);
}
else if (elem < curr->elem && elem > (curr->prev)->elem) {
pushInside(n);
}
else if (elem < curr->elem) {
curr = curr->prev;
addElem(elem);
}
} else {
pushBack(n);
}
}
void LList::pushFront(Node* n) {
head = n;
n->succ = curr;
curr->prev = n;
n->prev = 0;
curr = n;
size++;
}
void LList::pushInside(Node* n) {
(curr->prev)->succ = n;
n->succ = curr;
n->prev = curr->prev;
curr->prev = n;
size++;
}
void LList::pushBack(Node* n) {
if (!head) {
head = n;
} else {
tail->succ = n;
n->prev = tail;
}
tail = n;
curr = n;
size++;
}
LList::~LList() {
for (curr = head; curr;) {
Node* temp = curr->succ;
delete curr;
curr = temp;
}
}
LList& LList::operator=(LList& list) {
list.begin();
if (this != &list) {
for (curr = head; curr;) {
Node* temp = curr->succ;
delete curr;
curr = temp;
}
while (list.curr) {
addElem(list.getElem());
list.next();
}
}
return *this;
}
ostream& operator<<(ostream& os, LList& list) {
LList::Node* p = list.head;
os << "{ ";
while(p) {
os << p->elem << (p->succ ? ", " : "");
p = p->succ;
}
os << " }" << endl;
return os;
}
LList LList::operator+(LList& set) {
LList temp = *this;
temp += set;
return temp;
}
LList LList::operator+(int elem) {
*this += elem;
return *this;
}
int main() {
LList setA;
setA.addElem(1234);
setA.addElem(1435);
setA.addElem(1100);
LList setB;
setB.addElem(1234);
setB.addElem(1435);
setB.addElem(5100);
setB = setA + 1234; // 1st error here
LList setD;
setD = setA + setB; //2nd
cout << setA + setB << endl; //3rd
}
There is one glaring error in your code:
Node* begin() { curr = head; }
This code invokes undefined behavior, since you are not returning a value. It should be this:
Node* begin() { curr = head; return curr; }
In addition, you should pass your LList by const reference in functions that do not change the LList parameter:
For example:
LList::LList(LList& list);
LList& operator=(LList& list);
friend ostream& operator<<(ostream& os, LList& obj);
should be:
LList::LList(const LList& list);
LList& operator=(const LList& list);
friend ostream& operator<<(ostream& os, const LList& obj);
Please change these and the other functions to pass const references. If you want to see why you should change this, you will see the issue immediately if you tried to do this:
LList list1;
LList list2;
//...
std::cout << list1 + list2;
The operator << is looking for non-const LList objects, but the addition "inline" returns a temporary LList (which will mean that the return value will be const). The code will not compile due to your overloaded operator << accepting only non-const LList.
So you need to change your parameter in operator << to a const LList&.
You have a built in "current" pointer in your list class. This is a grave design error. You are unable to define your functions correctly because of this error.
It is a design error because with this design you cannot iterate over const lists, and this means, among other bad things, that you cannot do anything useful with temporary lists. So when you calculate setA + setB, you cannot assign it to anything,because to assign you need to iterate, so you need a non-const argument to operator= and to the copy constructor. But you cannot bind a temporary to a non-const reference.
Even if you bypass the public interface in the copy constructor and the copy assignment operator, and copy the list directly without using curr, you will have the same problem with any user function that must use the public interface. That is, setA + setB will not be usable as a function argument. You will need to assign it to some variable first, and then pass that variable to the function.
You also cannot take a list and pass it down to some function in the middle of an iteration, and expect to continue to iterate from the place you've left, because anything that iterates the list changes the curr pointer.
The best solution is to get rid of the curr member and make most of your arguments const LList&. While this is not the onky solution, there are many other drawbacks to having a current pointer built into a list class so I won't talk about them.
In order to iterate the list, you have to supply a separate object that can go back and forth over the list, and a separate variant of it that can go back and forth over a const list. This is called an iterator and you need to read up on this concept if you want to do anything in C++.
In your case iterators can be Node* and const Node*. You only need to provide member functions that return the first node in the list, which you already have. Real libraries do the same. They normally wrap the node pointer in a separate iterator class, for various reasons; but for a simple homework this is not necessary (though you can do it if you want).