I am implementing a generic singly linked list. It works with char and int, but not for string. What mistake have I made? I get an error:
C2679 binary '<<': no operator found which takes a right-hand operand of type 'T' (or there is no acceptable conversion)
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>
using namespace std;
template <typename T>
struct Node
{
T data;
Node*next;
//friend class List<T>;
};
template<typename T>
class List
{
public:
List() :headNode{ nullptr } {} // empty list constructor
~List() // destructor
{
Node<T>*current = headNode;
while (current)
{
Node<T>*temp = current;
current = current->next;
delete temp; cout << "\nDeleting Nodes!!!";
}
}
bool empty() const // is list empty?
{
return headNode == nullptr;
}
const T& front() const // get front element
{
return headNode->data;
}
void addFront(const T& e) // add to front of list
{
Node<T>* tempNode= new Node<T>;
tempNode->data = e;
tempNode->next = headNode;
headNode = tempNode;
}
void removeFront()
{
if (empty()) cout << "List is empty" << endl;
else
{
Node<T> *tempNode = headNode;
headNode = tempNode->next;
delete tempNode; cout << "\nDeleting Node!!!";
}
}
void printList()const
{
Node<T>*current = headNode;
while (current)
{
cout << current->data<<" |-> ";
current = current->next;
}
}
private:
Node<T> *headNode;
};
int main()
{
srand(time(NULL));
List<int> mylist;
for (int i = 0; i < 15; ++i)
{
mylist.addFront(rand()%200 + 20);
}
mylist.printList();
mylist.removeFront(); cout << endl;
mylist.printList();
List<string>family;
family.addFront("aaa");
family.addFront("bbb");
family.addFront("ccc");
family.addFront("ddd");
family.printList();
List<char> charlist;
charlist.addFront('a');
charlist.addFront('b');
charlist.addFront('c');
charlist.addFront('d');
charlist.printList();
return 0;
}
You need to include the header <string>.
#include <string>
where the operator << for streams and the class std::string is declared.
Related
Reading from a file, each line is stored in a list as an individual row. Each row contains two standard values and a variable amount stored in a list. Therefore each node has two values and a list. Initialization through operator>> works, but as soon as I try to run the loadfile function it crashes with the error: free(): double free detected in tcache 2 Aborted (core dumped)
Here is the code
#include <iostream>
#include "Resource.h"
#include "list.h"
#include "node.h"
using std::cout;
using rows = List<Resource>;
using row = Node<Resource>;
void loadFile(string idata, rows &res)
{
ifstream ifs(idata, ifstream::in);
while (ifs.good())
{
Resource s;
ifs >> s;
row *temp = new Node<Resource>(s);
res.insert(temp);
}
ifs.close();
}
int main()
{
rows resList;
loadFile("data.txt", resList);
cout << resList.getHead()->getValue();
}
this is the source for the class that stores the values, that will be wrapped in a Node template class.
#ifndef RESOURCE_H
#define RESOURCE_H
#include <iostream>
#include <fstream>
#include <string>
#include "list.h"
#include "node.h"
#include <stdio.h>
#include <algorithm>
using std::cout;
using std::istream;
using std::string;
class Resource
{
private:
string Name;
int amt;
List<string> clientList;
public:
Resource(string n, int a) : Name(n), amt(a) {}
Resource(string n) : Resource(n, 0) {}
Resource() : Resource("", 0) {}
string getName()
{
return this->Name;
}
int getAmt()
{
return this->amt;
}
void setName(string n)
{
this->Name = n;
}
void setAmt(int a)
{
this->amt = a;
}
friend ostream &operator<<(ostream &out, const Resource &r)
{
out << r.Name << ";" << r.amt;
List<string> temp = r.clientList;
for (Node<string> *app = temp.getHead(); app != NULL; app = app->getNext())
{
out << ';';
out << app->getValue();
}
return out;
}
friend istream &operator>>(istream &in, Resource &r)
{
string Name;
string amt;
string params;
string tempVar;
getline(in, Name, ';');
getline(in, amt, ';');
getline(in, params, '\n');
const int paramsOriginalLength = count(params.begin(), params.end(), ';');
for (int i = 0; i < paramsOriginalLength; i++)
{
r.clientList.insert(params.substr(0, params.find(';')));
params.erase(0, params.find(';') + 1);
}
r.setName(Name);
r.setAmt(stoi(amt));
return in;
}
};
#endif
EDIT: Since the problem might be caused by the data structure's defintion I will include the source of list.h and node.h
List:
#ifndef LIST_H
#define LIST_H
// Standard Template Linked List - List - by Eduardo Meli - 2020
#include "node.h"
#include <iostream>
using namespace std;
template <class T>
class List
{
private:
int length;
Node<T> *head;
public:
List(int length, Node<T> *head) : length(length), head(head) {}
List() : List(0, NULL) {}
Node<T> *getHead()
{
return this->head;
}
int getLength()
{
return this->length;
}
void insert(T value)
{
Node<T> *app = new Node<T>(value);
this->insert(app);
}
void insert(Node<T> *n)
{
if (head == NULL)
{
head = n;
length++;
return;
}
Node<T> *curr = head;
while (curr->getNext() != NULL)
{
curr = curr->getNext();
}
curr->setNext(n);
length++;
}
void deleteNode(Node<T> *n)
{
if (n == this->getHead())
{
this->head = head->getNext();
this->length = length - 1;
delete n;
return;
}
Node<T> *prev = head;
Node<T> *curr = head->getNext();
while (curr != NULL)
{
if (curr == n)
{
prev->setNext(curr->getNext());
length--;
return;
}
prev = curr;
curr = curr->getNext();
}
}
Node<T> *deleteNode(T value)
{
if (this->seekNode(value))
{
if (head->getValue() == value)
{
Node<T> *temp = head;
head = head->getNext();
length--;
return temp;
}
Node<T> *prev = head;
Node<T> *curr = head->getNext();
while (curr != NULL)
{
if (curr->getValue() == value)
{
prev->setNext(curr->getNext());
length--;
return curr;
}
prev = curr;
curr = curr->getNext();
}
}
return NULL;
}
void print()
{
Node<T> *nk = this->getHead();
while (nk != NULL)
{
cout << nk->getValue() << endl;
nk = nk->getNext();
}
}
~List()
{
Node<T> *ptr;
for (ptr = head; head; ptr = head)
{
head = head->getNext();
delete ptr;
}
}
};
#endif
And node:
#ifndef NODE_H
#define NODE_H
// Standard Template Linked List - Node - by Eduardo Meli - 2020
#include <fstream>
#include <iostream>
using namespace std;
template <class T>
class Node
{
private:
T value;
Node<T> *next;
public:
Node(T value, Node<T> *next) : value(value), next(next) {}
Node(T value) : Node(value, NULL) {}
Node() : Node(0, NULL) {}
T getValue()
{
return this->value;
}
Node<T> *getNext()
{
return this->next;
}
void setValue(T val)
{
this->value = val;
}
void setNext(Node<T> *n)
{
this->next = n;
}
friend ostream &operator<<(ostream &out, const Node &n)
{
out << n.value;
return out;
}
};
#endif
I was trying to implement the linked list stl but I always get runtime error if someone can help me solve this problem please.
What I was doing is when inserting an element I check if it's the first element if it is I make the head and tail point to it if not I use the node's next pointer to point to the new element and move the tail so it point to the last inserted element the error appears in the insert function.
#include <iostream>
using namespace std;
template<typename T>
struct Node {
T item;
Node *next = nullptr;
};
template<typename T>
class list {
static int sz;
Node<T> *head, *tail;
public:
void insert(T x) {
Node<T> new_node;
new_node.item = x;
if (!sz) {
*head = new_node;
*tail = new_node;
} else {
tail->next = &new_node;
*tail = new_node;
}
sz++;
}
int size() {
return sz;
}
friend ostream &operator<<(ostream &os, list<T> &o) {
while (o.head->next != nullptr) {
os << o.head->item << " ";
o.head = o.head->next;
}
return os;
}
};
template<typename T>
int list<T>::sz = 0;
int main() {
list<int> l;
l.insert(5);
l.insert(6);
l.insert(7);
cout << l.size() << endl;
cout << l << endl;
return 0;
}
I'm trying to implement a templated singly linked list and I'm fairly new to C++
#include <iostream>
#include <string>
#define NEWL "\n"
#define PRINT(s) std::cout << s
#define PRINTL(s) std::cout << s << NEWL
#define PRINTERR(e) std::cerr << e << NEWL
////// Class for a Node
template<class Data> class Node {
Node<Data>* next_ptr;
Data data;
public:
Node(Node<Data>* nxt_ptr) :next_ptr(nxt_ptr) {};
Node(Data d, Node<Data>* nxt_ptr) :data(d), next_ptr(nxt_ptr) {};
Node<Data>* get_next() { return next_ptr; }
Data& get_data() { return data; }
friend std::ostream& operator<<(std::ostream& out, const Node<Data>& node) {
out << node.data;
return out;
};
};
////// Class for a SinglyLinkedList
template<class Data> class SLinkedList {
Node<Data>* head_ptr;
int max_size;
public:
SLinkedList() : head_ptr(nullptr) {};
bool is_empty() {
return head_ptr == nullptr;
};
bool is_full() {
return get_size() == max_size;
};
int get_size() {
if (is_empty()) {
return 0;
}
int count = 0;
for (Node<Data>* it_ptr = head_ptr; it_ptr != nullptr; it_ptr = it_ptr->get_next()) {
count++;
}
return count;
};
void add(Data d) {
if (is_full()) {
throw std::exception("List is full!");
}
Node<Data> new_node(d, head_ptr);
head_ptr = &new_node;
};
void print_content() {
int count = 1;
PRINTL("This list contains:");
for (Node<Data>* it_ptr = head_ptr; it_ptr != nullptr; it_ptr = it_ptr->get_next()) {
PRINTL("\t["<< count << "]" << " at " << it_ptr << " : " << *it_ptr);
count++;
}
}
};
////// Main function
int main()
{
SLinkedList<int> sll;
sll.add(42);
sll.print_content();
}
I can't get this to work. Somehow iterating the list with for-loops does not work. It always results in an Reading Access Violation Exception about a pointer to 0xCCCCCCD0 and I have no idea how to fix this.
Your add function is incorrect
Node<Data> new_node(d, head_ptr);
creates a new function local Node in add. You then set head to the address of that local variable. When the function ends all local variables are destroyed so now head points to an object that no longer exists.
To fix that you need to use the new keyword to create a dynamic object that will live on after the function ends.
Node<Data>* new_node = new Node(d, head_ptr);
head_ptr = new_node;
The down side with this is you need to remember to call delete on all of the nodes you created in the list destructor.
You also have some other bugs in your code. You never set max_size in your constructor so using it at all except to give it a value is undefined behavior as we have no idea what the value of it is going to be. You also never increase the size of the list when you add nodes into the list.
I have created a linked list and in each list consists a node that holds a CarPart object. I believe I have everything working, except outputting the cout. I get the following errors
'CarPart::getPartNumber': non-standard syntax; use '&' to create a pointer to member (carpart.cpp line 34)
'CarPart::getDescription': non-standard syntax; use '&' to create a pointer to member (carpart.cpp line 35)
'CarPart::getPrice': non-standard syntax; use '&' to create a pointer to member (carpart.cpp line 36)
I have tried changing the osstream operator and have not been able to figure out the issue.
Main.cpp
#include "stdafx.h"
#include "List.h"
int main()
{
List partsList;
partsList.push_front(new CarPart("FL2016", "Oil Filter", 18.95));
partsList.push_front(new CarPart("RS12YC", "Spark Plug", 4.15));
partsList.push_front(new CarPart("D5941", "Digital Tire Guage", 12.15));
partsList.push_back(new CarPart("G19216", "Car Wash Solution", 8.15));
partsList.display();
cout << "now we are going to remove the first item in the list" << endl;
system("PAUSE");
partsList.pop_front();
partsList.display();
system("PAUSE");
cout << "now we are going to remove the LAST item from the list" << endl;
partsList.pop_back();
partsList.display();
system("PAUSE");
return 0;
}
List.h
#pragma once
#include "node.h"
class List
{
private:
int listSize;
Node* n;
Node* temp;
Node* head;
Node* tail;
public:
List();
void push_front(CarPart*);
void push_back(CarPart*);
void pop_front();
void pop_back();
void display();
~List();
};
List.cpp
#include "stdafx.h"
#include "List.h"
List::List()
{
}
void List::push_front(CarPart* dat)
{
if (listSize == 0) {
n = new Node;
n->setData(dat);
listSize++;
temp = n;
head = n;
tail = n;
}
else {
n = new Node;
n->setData(dat);
listSize++;
temp = head;
head = n;
n->setNext(temp);
n->setPrevious(nullptr);
temp->setPrevious(n);
temp = n;
}
}
void List::push_back(CarPart* dat)
{
if (listSize == 0) {
n = new Node;
n->setData(dat);
listSize++;
temp = n;
head = n;
tail = n;
}
else {
n = new Node;
n->setData(dat);
listSize++;
temp = tail;
temp->setNext(n);
n->setPrevious(temp);
// SET NEXT TO NULL
temp = n;
tail = temp;
}
}
void List::pop_front()
{
temp = head->getNext();
delete head;
head = temp;
listSize--;
}
void List::pop_back()
{
temp = tail->getPrevious();
delete tail;
tail = temp;
tail->setNext(nullptr);
listSize--;
}
void List::display()
{
Node* test = head;
for (int i = 0; i < listSize; i++) {
cout << test;
}
}
List::~List()
{
}
Node.h
#pragma once
#include "CarPart.h"
class Node
{
private:
CarPart* data;
Node* next;
Node* previous;
public:
Node();
CarPart* getData();
void setData(CarPart*);
void setNext(Node*);
void setPrevious(Node*);
Node* getPrevious();
Node* getNext();
void display();
~Node();
};
Node.cpp
#include "stdafx.h"
#include "Node.h"
Node::Node()
{
}
CarPart* Node::getData()
{
return data;
}
void Node::setData(CarPart* dat)
{
data = dat;
}
void Node::setNext(Node* nextNode)
{
next = nextNode;
}
void Node::setPrevious(Node* prev)
{
previous = prev;
}
Node * Node::getPrevious()
{
return previous;
}
Node * Node::getNext()
{
return next;
}
void Node::display()
{
cout << data;
}
Node::~Node()
{
}
CarPart.h
#pragma once
#include <iostream>
using namespace std;
class CarPart
{
private:
string partNumber;
string description;
double price;
public:
CarPart();
CarPart(string, string, double);
string getPartNumber();
string getDescription();
double getPrice();
~CarPart();
friend ostream& operator<<(ostream& os, CarPart* dt);
};
CarPart.cpp
#include "stdafx.h"
#include "CarPart.h"
CarPart::CarPart()
{
}
CarPart::CarPart(string n, string d, double p)
{
partNumber = n;
description = d;
price = p;
}
string CarPart::getPartNumber()
{
return partNumber;
}
string CarPart::getDescription()
{
return description;
}
double CarPart::getPrice()
{
return price;
}
ostream& operator<<(ostream& os, CarPart* dt)
{
os << dt->getPartNumber;
os << dt->getDescription;
os << dt->getPrice;
return os;
}
CarPart::~CarPart()
{
}
Update
I fixed the error below, but it is not outputting the car parts, the console just shows 00820788008207880082078800820788. I assume it is just the pointer, but not sure what I am doing wrong.
You are calling your get functions incorrectly. You are using dt->getPartNumber; instead of using dt->getPartNumber();
To call a method/function, you always put brackets, even if there is no arguments (dt->getPartNumber()). This line
os << dt->getPartNumber()
means "pass to os the value returned by calling getPartNumber".
Otherwise, it interprets dt->getPartNumber as a pointer to the getPartNumber function, which is a very different beast.
NOTE: For future questions, try to post only the minimum code that causes the error instead of the entire program, and try to mark the line where the error is raised. Google for SSCCE.
I am trying to use a class Student and declare it as a list type. I can pushback but without changing the List.h or Node.h how can I print the data in list2? The given print() function within List..h does not work :(
Node.h
#ifndef NODE_H
#define NODE_H
#include <string>
#include <iostream>
using namespace std;
template <typename T>
class Node {
private:
T data;
Node<T>* next;
public:
Node(T);
virtual ~Node(); // base class destructor must be virtual
template <typename U> friend class List;
};
template <typename T>
Node<T>::Node(T d) {
data = d;
next = NULL;
}
template <typename T>
Node<T>::~Node() {
}
#endif /* STRNODE_H */
List.h
#ifndef LIST_H
#define LIST_H
#include "Node.h"
// Singly linked list
template <typename T>
class List {
private:
Node<T>* head; // pointer to the first node
Node<T>* tail; // pointer to the last node
int count; // number of nodes in the list
public:
class OutOfRangeException{ }; // empty inner class for exception handling
List();
virtual ~List();
void push_back(T item);
void insert(int index, T item);
void remove(int index);
int indexOf(T item);
T get(int position); // OutOfRangeException is generated
bool isEmpty();
int size();
void print();
};
template <typename T>
List<T>::List() {
head = tail = NULL;
count = 0;
}
template <typename T>
List<T>::~List() {
Node<T>* discard;
while (head != 0) {
discard = head;
head = head->next;
delete discard;
}
}
// append an item at the end of the StrList
template <typename T>
void List<T>::push_back(T item) {
try {
Node<T>* newNode = new Node<T>(item);
if (head == 0) {
head = tail = newNode;
} else {
tail->next = newNode;
tail = newNode;
}
++count;
} catch (bad_alloc &e) {
cout << "memory allocation exception: " << e.what() << endl;
exit(1);
}
}
// insert an item at the specified index
template <typename T>
void List<T>::insert(int index, T item) {
try {
if (index < 0 || index > count) // push_back() if index == count
throw OutOfRangeException();
Node<T>* newNode = new Node<T>(item);
if (head == 0) { // empty
head = tail = newNode;
} else if (index == 0) { // at the start
newNode->next = head;
head = newNode;
} else if (index == count) { // at the end
tail->next = newNode;
tail = newNode;
} else { // insert in the middle
Node<T>* prevNode;
Node<T>* currNode = head;
for (int i = 0; i < index; i++) {
prevNode = currNode;
currNode = currNode->next;
}
// insert between 'prevNode' and 'currNode'
prevNode->next = newNode;
newNode->next = currNode;
}
++count;
} catch (bad_alloc &e) {
cout << "memory allocation exception: " << e.what() << endl;
exit(1);
}
}
// is the StrList empty?
template <typename T>
bool List<T>::isEmpty() {
return count == 0;
}
// remove the item at specified index
template <typename T>
void List<T>::remove(int index) {
if (index < 0 || index >= count)
throw OutOfRangeException();
if (index == 0) { // at the start
Node<T>* discard = head;
head = head->next;
delete discard;
} else {
Node<T>* prevNode;
Node<T>* currNode = head;
for (int i = 0; i < index; i++) {
prevNode = currNode;
currNode = currNode->next;
}
// remove 'currNode'
prevNode->next = currNode->next; // bypass
delete currNode;
if (index == count - 1) // last node was removed. Update 'tail'
tail = prevNode;
}
--count;
if (count == 0)
tail = NULL;
}
// retrieve the item at the given position of the StrList. position starts from 0.
// throws OutOfRangeException if invalid position value is given.
template <typename T>
T List<T>::get(int position) {
if (position < 0 || position >= count)
throw OutOfRangeException();
int loc = 0;
Node<T>* curr = head;
while (loc < position) {
++loc;
curr = curr->next;
}
return curr->data;
}
// Requirement:
// != operator of <class T> is used
template <typename T>
int List<T>::indexOf(T item) {
if (head == 0) {
return -1; // not found
} else {
int index = 0;
Node<T>* currNode = head;
while (currNode->data != item && currNode != NULL) {
currNode = currNode->next;
++index;
}
if (currNode == NULL) // not found thru the end
return -1;
else
return index;
}
}
// number of nodes in the StrList
template <typename T>
int List<T>::size() {
return count;
}
// Requirement:
// << operator for <class T> is used.
template <typename T>
void List<T>::print() {
cout << "*** StrList contents ***" << endl;
for (int i = 0; i < count; i++) {
cout << i << ": " << get(i) << endl;
}
}
#endif
Student.h
#include "List.h"
class Student {
private:
string name;
int id;
public:
Student();
Student(string a);
virtual ~Student();
friend ostream& operator<<(ostream &os, const Student& p);
bool operator!=(const Student &p) const;
bool operator==(const Student &p) const;
};
Student::Student() {
}
Student::Student(string a) {
name = a;
}
Student::~Student() {
}
ostream& operator<<(ostream &os, const Student& p) {
return os << p.name;
}
bool Student::operator==(const Student &p) const {
// Compare the values, and return a bool result.
if (name == p.name)
return true;
else
return false;
}
bool Student::operator!=(const Student &p) const {
return !(*this == p);
}
main.cpp
#include <iostream>
using namespace std;
#include "Student.h"
int main() {
cout << "\n*** StrList Test ***" << endl;
List<string> list;
list.push_back("zero");
list.push_back("one");
list.push_back("two");
list.push_back("three");
list.push_back("four");
list.push_back("five");
list.print();
list.insert(1, "inserted at position 1");
list.insert(0, "inserted at position 0");
list.insert(4, "inserted at position 4");
list.print();
cout << "removing at indexes 3, 0" << endl;
list.remove(3);
list.remove(0);
list.print();
list.insert(2, "inserted at position 2");
list.print();
cout << "five is at index " << list.indexOf("five") << endl;
cout << "two is at index " << list.indexOf("two") << endl;
//Test for my Student class implementation
// Student<string> st1; //Create new student Ryan Martin with id of 1
List<Student> list2;
Student stu("Ryan Martin");
list2.push_back(stu);
//list2.print();
//list2.push_back("Ryan");
//list2.PrintStudents(); //Test that the Student class successfully stored and can access
return 0;
}
The << operator must be defined for your Student class. To quote List.h:
// Requirement:
// << operator for <class T> is used.
template <typename T>
void List<T>::print() {
cout << "*** StrList contents ***" << endl;
for (int i = 0; i < count; i++) {
cout << i << ": " << get(i) << endl;
}
}
So in your Student class, you need to implement the operator<<(ostream &out);
Do it as a friend (friends are fun!):
friend std::ostream& operator<< (std::ostream &out, const Student &stu)
{
return out << stu.name << " id: " << stu.id << std::endl;
}
Here is a good reference:
http://www.learncpp.com/cpp-tutorial/93-overloading-the-io-operators/
If I understood you correctly, then you want to define operator<< for your student class, which you can do for example like this:
friend std::ostream & operator<<(std::ostream & os, const Student & s)
{
return os << s.name << " " << s.id << std::endl;
}
Note however that I have not tested this code and I haven't read all the snippets you posted,
so I might have understood you wrongly.
EDIT:
So after trying it out with Visual Studio, the full version of you student class should be like this:
#include "List.h"
class Student {
private:
string name;
int id;
public:
Student();
Student(string a);
virtual ~Student();
friend std::ostream & operator<<(std::ostream & os, const Student & s)
{
return os << s.name << " " << s.id << std::endl;
}
};
Student::Student() {
}
Student::Student(string a) {
name = a;
}
Student::~Student() {
}
Also not that you do not have to make the destructor in Student virtual unless you plan on having it as a base class for other classes.
the print function require an operator << to be defined on your student class and it's not the case
so define how a student will be display by << and it should work!