I'm writing this code for generic sorted list, and I have to write a filter method, without knowing what type of argument I will get. So I wrote it like that :
#include <iostream>
#include <cstring>
#include <string>
#include <functional>
#include "dummy.h"
using namespace std;
#ifndef SORT_H
#define SORT_H
template <class T>
class LinkedList {
struct Node {
Node(const T &in) : data(in) {}
T data;
Node * next;
};
class Iterator
{
Node *m_ptr; // pointer to current node in the list
public:
Iterator(Node * node) {
m_ptr = node;
}
Iterator& operator++() {
m_ptr = m_ptr -> next();
return *this;
}
Iterator operator++(int) {
Iterator temp(*this);
m_ptr = m_ptr -> next();
return temp;
}
bool operator==(const Iterator other) const {
return m_ptr==other.m_ptr; }
bool operator!=(const Iterator other) const
{ return m_ptr!=other.m_ptr; }
string& operator*()
{ return m_ptr->data(); }
operator bool()
{ return m_ptr!=0; }
};
Node * head;
public:
LinkedList() {
head = nullptr;
}
LinkedList(T value) {
head -> data = value;
head -> next = nullptr;
}
~LinkedList() {
while(head != nullptr) {
Node * n = head->next;
delete head;
head = n;
}
}
void operator = (T &t) {
head = t.head;
}
// LinkedList(LinkedList &list){
// Node * tmp = list.head;
// Node * curr = list.head -> next;
// while (curr) {
// tmp -> next = (Node*)malloc(sizeof(tmp-> next));
// tmp -> next = curr;
// tmp = tmp -> next;
// curr = curr -> next;
// }
// }
int length() {
int counter = 0;
Node * tmp = head;
while( tmp ) {
counter++;
tmp = tmp -> next;
}
return counter;
}
void insert(T value) {
if (head == nullptr) {
head = (Node*)malloc(sizeof(head));
head -> data = value;
head -> next = nullptr;
return;
}
Node* n = (Node*)malloc(sizeof(n));
n -> data = value;
Node* tmp = head;
while (tmp != nullptr) {
if (value > tmp -> data && tmp -> next != nullptr) {
if (tmp -> next -> data > value) {
Node * curr = tmp -> next;
tmp -> next = n;
n -> next = curr;
return;
} else {
tmp = tmp -> next;
}
} else if (value > tmp -> data && tmp -> next == nullptr) {
tmp -> next = (Node*)malloc(sizeof(tmp -> next));
n -> next = nullptr;
tmp -> next = n;
return;
} else if (value == tmp -> data && tmp -> next == NULL) {
tmp -> next = (Node*)malloc(sizeof(tmp -> next));
n -> next = nullptr;
tmp -> next = n;
return;
} else if (value == tmp -> data && tmp -> next != NULL) {
n -> next = tmp -> next;
tmp -> next = n;
return;
} else {
n -> next = tmp;
head = n;
return;
}
}
}
void remove(T value) {
Node* old = head -> next;
free(head);
head = old;
}
void print() {
Node *curr = head;
while (curr) {
cout << curr->data << endl;
curr = curr->next;
}
}
Iterator begin() {
return head->next();
}
Iterator end() {
return 0;
}
};
#endif
And my main looks like that :
#include <iostream>
#include "sortedList.h"
#include "dummy.h"
bool func(int num) {
if (num % 2 != 0) {
return false;
}
return true;
}
int main() {
std::cout << "Hello, World!" << std::endl;
Dummy teeth(24);
teeth.add(7);
Dummy slime(11);
slime.add(1);
Dummy josh(32);
LinkedList<Dummy> teeth_list;
teeth_list.insert(teeth);
teeth_list.insert(slime);
teeth_list.insert(josh);
int num = teeth_list.length();
cout << "The length is: " << num << endl;
teeth_list.remove(slime);
cout << "Now printing Dummy list" << endl;
teeth_list.insert(slime);
LinkedList<Dummy> new_int_list;
new_int_list = teeth_list;
teeth_list.print();
cout << "Now printing new_int_list" << endl;
new_int_list.print();
LinkedList <Dummy> dummy1;
dummy1 = dummy1.filter(teeth_list, &func);
// LinkedList <Dummy> dummy(teeth_list);
// cout << "Now printing new_dummy_list" << endl;
// new_int_list.print();
return 0;
}
The Dummy class looks like that:
#include <iostream>
#include <cstring>
#include <string>
#include <cmath>
using namespace std;
#ifndef DUMB_H
#define DUMB_H
class Dummy {
int num_of_teeth;
public:
Dummy(int num) {
num_of_teeth = num;
}
~Dummy() {};
void add(int num) {
num_of_teeth += num;
}
void remove() {
num_of_teeth --;
}
void operator = (Dummy &dumb) {
num_of_teeth = dumb.num_of_teeth;
}
bool operator < ( Dummy &dumb ) {
return num_of_teeth < dumb.num_of_teeth ? true : false;
}
bool operator > ( Dummy &dumb ) {
return num_of_teeth > dumb.num_of_teeth ? true : false;
}
bool operator == ( Dummy &dumb ) {
if ( dumb.num_of_teeth == num_of_teeth ) {
return true;
} else {
return false;
}
}
void print() {
int num = num_of_teeth;
while (num > 0) {
cout << "D";
if ((num-1) == (num_of_teeth/2)) {
cout << "\n";
}
num --;
if (num == 0) {
cout << "\n";
}
}
}
friend ostream& operator << (ostream& output, Dummy& dumb)
{
output << dumb.num_of_teeth;
return output;
}
};
#endif
And when I try to compile it I get the Error:
====================[ Build | exe_name | Debug ]================================
"C:\Program Files\JetBrains\CLion 2021.1.1\bin\cmake\win\bin\cmake.exe" --build C:\Users\User\CLionProjects\ex2.2\cmake-build-debug --target exe_name -- -j 3
Scanning dependencies of target exe_name
[ 33%] Building CXX object CMakeFiles/exe_name.dir/main.cpp.obj
In file included from C:\Users\User\CLionProjects\ex2.2\main.cpp:2:
C:\Users\User\CLionProjects\ex2.2\sortedList.h: In instantiation of 'LinkedList<T> LinkedList<T>::filter(LinkedList<T>&, B) [with B = bool (*)(int); T = Dummy]':
C:\Users\User\CLionProjects\ex2.2\main.cpp:36:45: required from here
C:\Users\User\CLionProjects\ex2.2\sortedList.h:112:21: error: cannot convert 'Dummy' to 'int' in argument passing
if (pred((curr -> data))) {
~~~~^~~~~~~~~~~~~~~~
mingw32-make.exe[3]: *** [CMakeFiles\exe_name.dir\build.make:81: CMakeFiles/exe_name.dir/main.cpp.obj] Error 1
mingw32-make.exe[2]: *** [CMakeFiles\Makefile2:94: CMakeFiles/exe_name.dir/all] Error 2
mingw32-make.exe[1]: *** [CMakeFiles\Makefile2:101: CMakeFiles/exe_name.dir/rule] Error 2
mingw32-make.exe: *** [Makefile:136: exe_name] Error 2
Where should I change the code to make it work? And how?
**edit: After I changed the function in main to:
bool func(Dummy num) {
int number = num.get();
if (number % 2 != 0) {
return false;
}
return true;
}
It compiles but returns an unending list of unknown numbers.. like-
16740248
16711872
16740296
16740248
16711872
16740296
16740248
16711872
16740296
16740248
16711872
16740296
16740248
16711872
Process finished with exit code -1073741510 (0xC000013A: interrupted by Ctrl+C)
Where in the code do I try to reach a forbidden memory? or a corrupted one?
You pass an entire Dummy to the predicate function when you call pred((curr -> data)
. pred
, coming from the line dummy1 = dummy1.filter(teeth_list, &func);
, is a function expecting an int, which it doesn't get.
There are a couple of potential fixes.
int
in Dummy
(presumably returning the number of teeth) should work as well.The conversion operator approach seemed to work for me. I inserted
operator int() { return num_of_teeth; }
into the Dummy
class in the public section.
Whether that is good style is debatable. It may be unexpected that a Dummy is also an int. There is perhaps also an argument that the predicate function should work on the entire node data, but that is debatable: A general, reusable function that can handle everything int-oid has its merits as well. Since C++11 you can mitigate the unexpectedness of a conversion to int
by making it explicit: It is still possible but requires a static cast.
As for the rest of the code:
head = t.head;
— a shallow copy, sharing all nodes — leads to double deletes on each node when the lists go out of scopenext
Make sure to write extensive tests for such a container class with wild inserts and deletes, at the beginning, the end etc. Make sure to cover all edge cases with empty lists. Containers are hard to get perfectly correct without rigorous tests.