I've made a basic linked list, the list had originally held integers, I'm trying to change the list to a template class.
My node class is called TLLNode,
TLLNODE.h
#pragma once
template<class T>
class TLLNode{
friend class TLL;
public:
TLLNode(T data);typedef TLLNode<T>* TLLPtr;
private:
TLLNode<T> data;
TLLNode *next;
};
template<class T>
TLLNode<T>::TLLNode(T dataIn) : data(dataIn){
}
template<class T>
using TLLNode<T>* TLLPtr;
and my list class to initialize and implement my functions is called TLL
TLL.h
#pragma once
#include <iostream>
#include"TLLNode.h"
using std::cout;
using std::endl;
template<class T>
class TLL{
public:
TLL();
TLL(const TLL&);
void insert(T);
void display();
~TLL();
private:
TLLPtr head;
TLLPtr newNode;
TLLPtr curr;
int size;
};
template<class T>
TLL<T>::TLL() : head(NULL), size(0){
}
// Not implemented yet
template<class T>
TLL<T>::TLL(const TLL& obj){
}
template<class T>
void TLL<T>::insert(T data){
if (head == NULL)
head = new TLLNode(data);
else{
newNode = new TLLNode(data);
newNode->next = head;
head = newNode;
}
}
template<class T>
void TLL<T>::display(){
curr = head;
while (curr != NULL){
cout << curr->data << endl;
curr = curr->next;
}
}
template<class T>
TLL<T>::~TLL(){
while (head != NULL){
curr = head;
head = head->next;
delete curr;
}
}
I had been using typedef TLLNode* TLLPtr; when the list was of type int, but typedef for templates seems to be illegal.
I've tried a few different ways to get this to work and can't get any solution to work, I came across this post
using, I've tried to use this solution without success, the code seems identical to what I want to do, bar the use of pointers.
I haven't tried the older solution in that post yet, using a struct.
Are either solutions going to work for me and if not is there an alternative?
I realize there's probably mistakes in my code other than the issue I'm discussing, I'd like to try to figure out my own mistakes, so if it's not related to my issue or directly preventing me from proceeding, I'll figure it out when I get to it.
You should define TLLPtr as follows:
template<class T>
using TLLPtr = TLLNode<T>*;
And everywhere in the definition of TLL use TLLPtr<T> instead of just TLLPtr (and also change TLLNode to TLLNode<T>).
Update: I've also noticed that you have TLLNode<T> data; in TLLNode. You can't define a member of the class having the type of class itself, you probably meant T data;.
Related
I'm learning C++ with some exercises from a book that I found a while ago. My task is described below and I've tried to find a work around for returning a template node I created for the template function getLastNode to add a node at the end of the list. Is it possible to do that, currently I can't find a way to let's call it explain the compiler what TNode is as a struct within a class return value.
I might have the best way to declare nodes in this code. Perhaps, a struct within a class can complicate class template methods implementations. Do you feel there's another strategy? Please let me know
Cheers!
/* Implement the data structure dynamic doubly linked list (DoublyLinkedList<T>) - list,
* the elements of which have pointers both to the next and the previous elements. Implement
* the operations for adding, removing and searching for an element, as well as inserting
* an element at a given index, retrieving an element by a given index and a method, which returns an array with the elements of the list*/
#include <iostream>
template<typename TValue>
class List{
struct TNode{
TValue value;
TNode *previous;
TNode *next;
}Node;
public:
List();
~List();
void addNode(TValue);
private:
TNode *root;
TNode getLastNode(TNode);
};
template<typename TValue>
List<TValue>::List():root(0) {}
template<typename TValue>
List<TValue>::~List<TValue>(){
}
template<typename TValue>
TNode List<TValue>::getLastNode(TNode node){
if(node.next==nullptr)
return node;
else
getLastNode(node.next);
}
template<typename TValue>
void List<TValue>::addNode(TValue value){
const TNode last = getLastNode(root);
last.next = Node;
last.next->value = value;
}
int main(){
List<int> test;
return 0;
}
To return TNode for the getLastNode method I had to add auto to its class method declaration.
Credits: #JaMiT
template<typename TValue>
auto List<TValue>::getLastNode(TNode node){
if(node.next==nullptr)
return node;
else
getLastNode(node.next);
}
I have been learning and playing around C++ (mostly, pointers and dynamic memory allocation) for few days and I tried to create a generic class for linked list.
The classes
#include <cstdint>
#define _LINKEDLIST_DEFAULT_MAX_SIZE 2147483647L
template <typename T>
class LinkedList;
template <typename T>
class LinkedListNode;
template <typename T>
class LinkedListNode final
{
private:
LinkedListNode<T> *nextNode{nullptr};
friend LinkedList<T>;
public:
T data{};
};
template <typename T>
class LinkedList final
{
private:
LinkedListNode<T> *firstNode{nullptr};
std::int32_t maxLength{};
std::int32_t currentLength{};
public:
LinkedList(std::int32_t max_size = _LINKEDLIST_DEFAULT_MAX_SIZE)
{
maxLength = max_size;
}
void addFirst(LinkedListNode<T> *nodePtr)
{
if (firstNode == nullptr)
{
firstNode = nodePtr;
return;
}
nodePtr->nextNode = firstNode;
firstNode = nodePtr;
}
void clerList()
{
// code of releasing occupied heap memory back
}
}
Main method
int main()
{
LinkedList<short> *head{new LinkedList<short>()};
LinkedListNode<short> *node1{new LinkedListNode<short>()};
LinkedListNode<short> *node2{new LinkedListNode<short>()};
node1->data = 1;
node2->data = 2;
head->addFirst(node1);
head->addFirst(node2);
return 0;
}
And this works as properly so far as variables in my debugger shows expected results.
But my issue is how could I write my clearList() method on LinkedList<T> class? I can traverse through LinkedListNode<T> objects and release their memory back calling delete(), but calling delete(this) from clearList() to release back the memory of LinkedList<T> object at first sounds like suiciding since it tries to delete the object which it belongs to. (Note that some simple validation logics have not yet been put into the code)
Do you have any ideas to make this happen :)
I have linked list class that implements a node structure, like this:
template<class T>
class LinkedList
{
public:
struct Node {
T value;
Node *next;
};
int Length;
Node *head;
Node *tail;
LinkedList() {
Length = 0;
Node* head = nullptr;
Node* tail = nullptr;
}
};
I tried accessing the node Node structure from the driver file like so:
#include "LinkedList.h"
template<class T>
void foo(LinkedList<T> list) {
LinkedList<T>::Node* a = list.head; // does not work
LinkedList<int>::Node* b = list.head; // works (if T is int of course)
}
Using a template T does not work (it gives me "identifier not found" error message), while directly specifying the correct datatype works. Why is that? Is there a way to avoid the error?
Use typename LinkedList<T>::Node* a = ...
The problem is that not knowing what exactly T is, the compiler can’t be sure LinkedList<T>::Node is indeed a type (LinkedList could be specialized for T so the definition doesn’t help). You need to instruct it to treat it that way.
I'm trying to write my own code for the erase function used in dynamic structures (lists specifically) of the stl library for a school project
What I had in mind was to do a loop until i found the node prior to the one i wanted to delete.
while (loop->next!= NULL){
if (loop->next==pValue){
break;
}
else {
loop->next;
}
}
prev=loop;
delete loop;
Then I want to update its pointer and instead of having it point to the node to be deleted, i want it to point to the node after the one i'm going to delete.
So can i do this?
*(prev->next)=*(pValue->next);
in case i can't, what should i do?
Here's my function erase
template <class T>
void list<T>::erase(pos pValue){
list<T>::pos prev;
list<T>::pos temp=pValue->next;
list<T>::pos loop=list<T>::first();
while (loop->next!= NULL){
if (loop->next==pValue){
break;
}
else {
loop->next;
}
}
prev=loop;
delete loop;
*(prev->next)=*(pValue->next);
delete list<T>::get(pValue);
}
And here's part of my class list
template <class T>
class list {
node<T> *pFirst;
int n;
public:
typedef node<T> *pos;
void erase(pos pValue);
};
And the structure of the node:
template <class T>
class node {
public:
T info;
node<T> *next;
};
I've been working on updating my old templated linked list to be able to take a complex data type. But I have no idea how to make it be able to return the data element in the node class. Currently the code for my node class looks like this:
using namespace std;
#ifndef Node_A
#define Node_A
template <class T>
class Node
{
public:
Node();
~Node();
T getData();
Node* getNext();
void setData(T);
void setNext(Node*);
private:
Node *next;
T data;
};
template <class T>
Node<T>::Node()
{
next = NULL;
return;
}
template <class T>
Node<T>::~Node()
{
return;
}
template <class T>
T Node<T>::getData()
{
return data;
}
template <class T>
Node<T>* Node<T>::getNext()
{
return next;
}
template <class T>
void Node<T>::setData(T a)
{
data = a;
return;
}
template <class T>
void Node<T>::setNext(Node* a)
{
next = a;
return;
}
#endif
Now this works perfectly fine if the data type T is a primitive but if you use a non-primitive like say a struct it would give a runtime error. I presume because structs don't do operator overloading for = operator. Is there a simple way of fixing this without completely overhauling the class?
It's not about overloading the = operator, it's about implementing the assignment operator for the struct. If you do that, you won't need to change your Node class, unless I've missed something else.
The above assumes that you'll be making copies of the data inside the Node. Alternatively, you can pass the data by reference. In this case, you need to be careful that the data doesn't get deleted before the Node object is deleted, otherwise you'll get a crash when trying to access a deleted data object from your Node.