I am trying to create a linked list of arrays without using the STL. However, I am having difficulties passing the array to my Linked List...
When I compile I get the error listed above. How do I need to pass the array to the linked list? Thanks! (The code in question is marked by **, please remove if testing.)
SinglyLinkedList.h
#pragma once
#ifndef SinglyLinkedList_h
#define SinglyLinkedList_h
#include<iostream>
template <typename Type>
struct node
{
Type value;
node *next;
};
template <typename Object>
class SinglyLinkedList
{
private:
node<Object> *head;
public:
SinglyLinkedList();
~SinglyLinkedList();
bool insert(Object x);
bool empty();
};
template <typename Object>
SinglyLinkedList<Object>::SinglyLinkedList()
{
this->head = NULL;
}
template <typename Object>
bool SinglyLinkedList<Object>::insert(Object x)
{
node<Object> *temp = new node<Object>;
temp->value = x;
temp->next = NULL;
if (this->head==NULL)
{
this->head = temp;
}
else
{
node<Object> *S = this->head, *P = S;
while ((S->value < temp->value)&&(S != NULL))
{
S = S->next;
P = S;
}
if(S == NULL)
temp->next = P;
else
{
temp->next = S;
P->next = temp;
}
}
return true;
}
template <typename Object>
bool SinglyLinkedList<Object>::empty()
{
if(this->head == NULL)
return true;
else
return false;
}
template <typename Object>
SinglyLinkedList<Object>::~SinglyLinkedList()
{
delete this->head;
}
#endif
DynamicArrayClass.h
#pragma once
#ifndef DynamicArrayClass_h
#define DynamicArrayClass_h
#include<iostream>
template <class T>
class DynamicArrayClass
{
private:
T *array;
int size, numItems;
public:
DynamicArrayClass(int newSize)
{
size = newSize;
numItems=0;
array = new T[size];
}
int GetSize(){ return size;}
int GetNumItems() const { return numItems; }
bool isEmpty() const { return numItems==0; }
bool isFull() const { return numItems==size; }
bool addItem (const T &object)
{
if(isFull())
{
return false;
}
else
{
array[numItems++] = object;
return true;
}
}
const T& getItem(int index) {return array[index];}
void makeEmpty()
{
numItems = 0;
}
~DynamicArrayClass()
{
if(array !NULL)
delete [] array;
}
};
#endif
main.cpp
#include "DynamicArrayClass.h"
#include "SinglyLinkedList.h"
#include "stopwatch.h"
#include<iostream>
int main()
{
int totalCapacity = 0;
int arrayAddSize = 0;
while(totalCapacity < 10000)
{
if(totalCapacity==0)
{
DynamicArrayClass<int> *array1 = new DynamicArrayClass<int>(25);
totalCapacity = 25;
SinglyLinkedList<DynamicArrayClass<int>> *list = new SinglyLinkedList<DynamicArrayClass<int>>();
for(int i = 0; i<25; i++)
{
array1->addItem(1);
}
**list->insert(*array1);**
}
else
{
arrayAddSize = (totalCapacity/2);
totalCapacity = totalCapacity + arrayAddSize;
DynamicArrayClass<int> *array = new DynamicArrayClass<int>(arrayAddSize);
SinglyLinkedList<DynamicArrayClass<int>> *list = new SinglyLinkedList<DynamicArrayClass<int>>();
for(int i=0; i <arrayAddSize; i++)
{
array->addItem(1);
}
}
}
return 0;
}
The problem is in this part of insert:
node<Object> *temp = new node<Object>;
where the node contains an Object. To construct that, the Object needs a default constructor.
Perhaps you can add a constructor to node that copies the value it has to store? That would make it, for example:
node<Object> *temp = new node<Object>(x, NULL);
node<Object> *temp = new node<Object>;
This line in SinglyLinkedList::insert causes the error I assume. The problem is, that your node struct looks like this:
template <typename Type>
struct node
{
Type value;
node *next;
};
That Type value; will be default constructed by the new node<Object> call. Provide an appropriate constructor for the node struct and you should be fine.
Related
I am currently writing a program to mimic the functions of a linked list. I think the the code is crashing due to memory leaks, but I cannot figure out where they might be. I have tried deleting after every new, but when I delete it causes the functions to not operate correctly. I also think I my push_back() function may not be operating correctly, because my output does not match the output of std::list. Any help would be greatly appreciated. Thanks!
When I run the program this is the output I receive:
4000
33
100
3
33
100
423
423
100
33
200
100
4000
double free or corruption (fasttop)
Aborted (core dumped)
This is the output I am expecting:
4000
33
100
3
33
100
423
423
100
423
33
200
100
Header File:
#ifndef MYLIST_H
#define MYLIST_H
#include <iostream>
using std::cout;
using std::endl;
using std::cin;
using std::cerr;
using std::string;
template <typename T>
class Node
{
public:
T m_element;
Node<T> *m_prev;
Node<T> *m_next;
// Helps you make a dummy/sentinel/junk node
Node(Node<T> *in_prev, Node<T> *in_next):
m_prev(in_prev), m_next(in_next){}
Node(const T &x, Node<T> *in_prev, Node<T> *in_next):
m_element(x), m_prev(in_prev), m_next(in_next){}
};
template <typename T>
class MyList
{
private:
Node<T> *m_sentinel = nullptr;
int m_size;
public:
// A list size of 0 will have 1 sentinel node.
MyList();
~MyList();
MyList<T> & operator=(const MyList<T> &source);
MyList(const MyList<T> &source);
T & front();
T & back();
void assign(int count, const T &value);
// Default list size of 0, with one sentinel node, as above in constructor
void clear();
void push_front(const T &x);
void push_back(const T &x);
void pop_back();
void pop_front();
// Simplified version that only takes one int position.
// Inserts before element at position i.
// Not exactly like std::
// You do NOT need a special case for 0-big lists (i.e., no if size == 0)
// You should be able to insert in 0 big list.
void insert(int i, const T &x);
// Removes all elements in list that are equal to value.
// You do NOT need a special case for 0-big lists (i.e., no if size == 0).
void remove(T value);
// Removes element at position i.
void erase(int i);
void reverse();
bool empty();
int size();
// Mimicking C++ iterator trickery from here down.
// You don't need to edit these two.
int begin()
{
return 0;
}
int end()
{
return size();
}
};
#include "MyList.hpp"
#endif
HPP File:
template <typename T>
MyList<T>::MyList()
{
m_sentinel = new Node<T>(nullptr, nullptr);
m_sentinel->m_next = m_sentinel;
m_sentinel->m_prev = m_sentinel;
m_size = 0;
}
template <typename T>
MyList<T>::~MyList()
{
Node<T> *temp;
for(int i = 0; i < m_size; i++)
{
temp = m_sentinel->m_prev;
delete m_sentinel->m_prev;
m_sentinel->m_prev = temp->m_prev;
}
delete m_sentinel;
m_sentinel = nullptr;
}
template <typename T>
MyList<T> & MyList<T>::operator=(const MyList<T> &source)
{
this->~MyList();
Node<T>* tempNode = new Node<T>(nullptr, nullptr);
tempNode = source.m_sentinel->m_next;
m_sentinel = new Node<T>(nullptr, nullptr);
m_sentinel->m_next = m_sentinel;
m_sentinel->m_prev = m_sentinel;
for(int i = 0; i < source.m_size; i++)
{
this->push_back(tempNode->m_element);
tempNode = tempNode->m_next;
}
}
template <typename T>
MyList<T>::MyList(const MyList<T> &source)
{
*this = source;
}
template <typename T>
T & MyList<T>::front()
{
return m_sentinel->m_next->m_element;
}
template <typename T>
T & MyList<T>::back()
{
return m_sentinel->m_prev->m_element;
}
template <typename T>
void MyList<T>::assign(int count, const T &value)
{
while(m_size)
{
this->pop_back();
}
for(int i = 0; i < count; i++)
{
this->push_back(value);
}
m_size = count;
}
// Default list size of 0, with one sentinel node, as above in constructor
template <typename T>
void MyList<T>::clear()
{
while(m_size)
{
this->pop_back();
}
}
template <typename T>
void MyList<T>::push_front(const T &x)
{
Node<T> *tempNode = new Node<T>(x, m_sentinel, m_sentinel->m_next);
m_sentinel->m_next->m_prev = tempNode;
m_sentinel->m_next = tempNode;
m_size++;
}
template <typename T>
void MyList<T>::push_back(const T &x)
{
Node<T> *tempNode = new Node<T>(x, m_sentinel->m_prev, m_sentinel);
m_sentinel->m_prev = tempNode;
tempNode->m_prev->m_next = tempNode;
m_size++;
}
template <typename T>
void MyList<T>::pop_back()
{
//edit
if(m_size != 0)
{
//check if temp node is needed
//Node<T> *tempNode = m_sentinel->m_prev;
m_sentinel->m_prev = m_sentinel->m_prev->m_prev;
delete m_sentinel->m_prev->m_next;
m_sentinel->m_prev->m_next = nullptr;
m_sentinel->m_prev->m_next = m_sentinel;
//delete tempNode;
m_size--;
}
}
template <typename T>
void MyList<T>::pop_front()
{
if(m_size != 0)
{
m_size--;
m_sentinel->m_next = m_sentinel->m_next->m_next;
delete m_sentinel->m_next->m_prev;
m_sentinel->m_next->m_prev = nullptr;
m_sentinel->m_next->m_prev = m_sentinel;
}
}
// Simplified version that only takes one int position.
// Inserts before element at position i.
// Not exactly like std::
// You do NOT need a special case for 0-big lists (i.e., no if size == 0)
// You should be able to insert in 0 big list.
template <typename T>
void MyList<T>::insert(int i, const T &x)
{
if(i >= 0 && i < m_size)
{
Node<T> *tempNode = m_sentinel;
for(int j = 0; j < i; j++)
{
tempNode = tempNode->m_next;
}
Node<T> *insertNode = new Node<T>(x, tempNode, tempNode->m_next);
tempNode->m_prev->m_next = insertNode;
tempNode->m_next->m_prev = insertNode;
m_size++;
}
}
// Removes all elements in list that are equal to value.
// You do NOT need a special case for 0-big lists (i.e., no if size == 0).
template <typename T>
void MyList<T>::remove(T value)
{
Node<T> *currentNode = m_sentinel->m_next;
Node<T> *tempNode = currentNode->m_next;
int counter = m_size;
for(int i = 0; i < counter; i++)
{
if(currentNode->m_element == value)
{
currentNode->m_prev->m_next = currentNode->m_next;
currentNode->m_next->m_prev = currentNode->m_prev;
tempNode = currentNode->m_next;
m_size--;
delete currentNode;
currentNode = nullptr;
currentNode = tempNode;
}
else
{
currentNode = currentNode->m_next;
}
}
}
// Removes element at position i.
template <typename T>
void MyList<T>::erase(int i)
{
if(i >= 0 && i < m_size)
{
Node<T> *currentNode = m_sentinel->m_next;
for(int j = 0; j < i; j++)
{
currentNode = currentNode->m_next;
}
currentNode->m_prev->m_next = currentNode->m_next;
currentNode->m_next->m_prev = currentNode ->m_prev;
delete currentNode;
currentNode = nullptr;
m_size--;
}
}
template <typename T>
void MyList<T>::reverse()
{
Node<T> *nextNode = m_sentinel->m_next;
Node<T> *prevNode = m_sentinel->m_prev;
for(int i = 0; i < (m_size/2); i++)
{
std::swap(nextNode->m_element, prevNode->m_element);
nextNode = nextNode->m_next;
prevNode = prevNode->m_prev;
}
}
template <typename T>
bool MyList<T>::empty()
{
if(m_size==0)
{
return true;
}
else
{
return false;
}
}
template <typename T>
int MyList<T>::size()
{
return m_size;
}
Driver to test if MyList function works like std::list:
#include <list>
#include "MyList.h"
int main()
{
MyList<int> l;
//std::list<int> l;
l.push_back(4000);
l.push_back(200);
l.push_back(100);
cout << l.front() << endl;
l.front() = 33;
cout << l.front() << endl;
cout << l.back() << endl;
cout << l.size() << endl;
l.push_back(4000);
l.push_back(200);
l.push_back(100);
cout << l.front() << endl;
cout << l.back() << endl;
l.push_front(423);
cout << l.front() << endl;
MyList<int> sink;
sink = l;
cout << sink.front() << endl;
cout << sink.back() << endl;
l.insert(l.begin(), 3);
l.insert(l.end(), 20);
l.pop_front();
l.reverse();
int j = 0;
for(auto i = 0; i < l.size(); i++)
{
cout << l.back() << endl;
l.pop_back();
j++;
}
return 0;
}
Thanks!
UPDATED COPY CONSTRUCTOR AND ASSIGNMENT OPERATOR
template <typename T>
MyList<T> & MyList<T>::operator=(const MyList<T> &source)
{
MyList<T> temp(source);
std::swap(temp.m_sentinel, m_sentinel);
return *this;
}
template <typename T>
MyList<T>::MyList(const MyList<T> &source)
{
Node<T> *temp = source.m_sentinel;
m_sentinel = nullptr;
while(temp != nullptr)
{
push_back(temp->m_element);
}
}
Now it gives me a segfault and crashes when calling the push_back() function. I'm lost. I've tried implementing this several different ways but every time I either get a double free or a segfault.
C++ noob here. I trying to create a student information program by implementing
a Linked-List class as its data structure.
LinkedList.h
#pragma once
#include <stdexcept>
template <typename T>
class LinkedList
{
private:
struct Node
{
T elem;
Node *prev;
Node *next;
};
Node *header;
Node *trailer;
int size;
public:
LinkedList()
{
header = new Node;
trailer = new Node;
header->next = trailer;
trailer->prev = header;
}
~LinkedList()
{
while (!isEmpty())
removeFirst();
delete header;
delete trailer;
}
const int& n_elem() const
{
return size;
}
const bool isEmpty() const
{
return size == 0;
}
const T& getFirst() const
{
if (isEmpty())
throw std::out_of_range("List is empty.");
return header->next->elem;
}
const T& getLast() const
{
if (isEmpty())
throw std::out_of_range("List is empty.");
return trailer->prev->elem;
}
void addFirst(const T& item)
{
addBetween(item, header, header->next);
}
void addLast(const T& item)
{
addBetween(item, trailer->prev, trailer);
}
void addAt(int index, const T& item)
{
Node *node = header;
for (int i = 0; i < index; i++)
node = node->next;
addBetween(item, node, node->next);
}
const T removeFirst()
{
if (isEmpty())
throw std::out_of_range("List is empty.");
return remove(header->next);
}
const T removeLast()
{
if (isEmpty())
throw std::out_of_range("List is empty.");
return remove(trailer->prev);
}
const T removeAt(int index)
{
if (isEmpty())
throw std::out_of_range("List is empty.");
Node *node = header;
for (int i = 0; i < index; i++)
node = node->next;
return remove(node->next);
}
const T& itemAt(int index) const
{
if (isEmpty())
throw std::out_of_range("List is empty.");
Node *node = header;
for (int i = 0; i < index; i++)
node = node->next;
return node->next->elem;
}
protected:
void addBetween(const T& item, Node *predecessor, Node *successor)
{
Node *newest = new Node;
newest->prev = predecessor;
newest->next = successor;
predecessor->next = newest;
successor->prev = newest;
size++;
}
const T remove(Node *node)
{
Node *predecessor = node->prev;
Node *successor = node->next;
predecessor->next = successor;
successor->prev = predecessor;
T oldItem = node->elem;
size--;
delete node;
return oldItem;
}
};
Student class is defined below.
Program.cpp
#include "stdafx.h"
#include <iostream>
#include <string>
#include "LinkedList.h"
using namespace std;
class Student
{
public:
string name;
string id;
int score;
static const int total = 100;
double grade;
Student(string n, string i, int s)
{
name = n;
id = i;
score = s;
grade = getGrade(score);
}
private:
double getGrade(int score)
{
return (23.0 / 3.0 - ((20.0 * score) / (3.0 * total)));
}
};
LinkedList<Student> l;
int main()
{
//Some code here
return 0;
}
I don't know the reason why
LinkedList<Student> l;
produces an error:
LinkedList<Student>::Node::Node(void)': attempting to reference a deleted function
But when I use:
LinkedList<Student*> l;
there's no error.
Please help.
I'm using Visual Studio 2015.
And sorry for bad English.
In LinkedList<Student>, the inner struct Node looks like this:
struct Node
{
Student elem;
Node *prev;
Node *next;
};
so every Node contains a Student.
However, you'll note that Student has a constructor that takes arguments:
Student(string n, string i, int s)
and it does not have a constructor that does not take arguments.
So if you were to write new Node, the computer would create a Node, and as part of that it would create a Student, but it can't do that because it doesn't have any arguments to give to Student's constructor.
That's (approximately) what "deleted function" means here - normally the compiler would make a Node constructor for you, but in this case it can't.
And so new Node doesn't work, because Node doesn't have a constructor.
Probably the easiest fix here is just to give Student a no-argument constructor as well - something like:
Student()
{
name = "";
id = "";
score = 0;
grade = getGrade(score);
}
I made a linked list class to practice generic programming. The following code compiles, but my test in the main isn't printing anything to the console, like it should be. Any idea why? I know that Stack Overflow doesn't like the "fix my bug" posts, but I'm really at a loss here.
#include <iostream>
template <class T> class List {
public:
List();
~List();
int getSize();
void push_back(T);
bool contains(T);
private:
struct node {
T val;
node* next;
};
int size;
node* firstNodePtr;
node* lastNodePtr;
};
template <class T> List<T>::List() {
size = 0;
firstNodePtr = NULL;
lastNodePtr = NULL;
}
template <class T> List<T>::~List() {
node* curNodePtr = firstNodePtr;
node* nextNodePtr;
while (curNodePtr) {
nextNodePtr = curNodePtr->next;
delete curNodePtr;
curNodePtr = nextNodePtr;
}
}
template <class T> int List<T>::getSize() {
return size;
}
template <class T> void List<T>::push_back(T newElement) {
if (size == 0) {
firstNodePtr = new node;
firstNodePtr->next = lastNodePtr;
firstNodePtr->val = newElement;
++size;
} else {
node* newNode = new node;
lastNodePtr->next = newNode;
newNode->val = newElement;
newNode->next = NULL;
++size;
}
}
template <class T> bool List<T>::contains(T thisElement) {
node* curNodePtr = firstNodePtr;
while (curNodePtr) {
if (curNodePtr->val == thisElement)
return true;
curNodePtr = curNodePtr->next;
}
return true;
}
int main (int argc, char* const argv[]) {
List<int> myList;
myList.push_back(5);
myList.push_back(18);
std::cout << myList.getSize() << std::endl;
std::cout << myList.contains(18);
return 0;
}
Look here:
if (size == 0){
firstNodePtr = new node;
firstNodePtr->next = lastNodePtr;
firstNodePtr->val = newElement;
++size;
}
You forgot to assign a value to lastNodePtr. So when you try to dereference it in the second call to push_back, you get undefined behavior.
In the block handling the creation of the initial node in push_back,
you don't want this line:
firstNodePtr->next = lastNodePtr;
Also, you need to set lastNodePtr = firstNodePtr; at the end of push_back
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...
So I have this linked list class that does a great job on it's own functionally, however is pretty disgusting when it comes to actual memory usage (leaks, leaks everywhere).
So I'm going through implementing a basic smart pointer class into it so as to better handle memory, however I've hit a few rough points on the actual implementation part of this idea.
I've only specifically included what I think is relevant to the issue, however, if there is any parts not included that may prove useful, ask and I can post the whole thing.
main.cpp:
int main()
{
smartLinkedList<char*> moo2;
moo2.insertAtFront("tail");
moo2.insertAtFront("one");
moo2.insertAtFront("head");
for(int j = 0; j < moo2.length() ; j++)
cout << moo2.goToFromFront(j) << endl;
cin.ignore(1);
return 0;
}
smartLinkedList.h:
template <class type>
class smartLinkedList
{
private:
int size;
sPtr<node<type>> head;
public:
smartLinkedList(): head(NULL), size(0) {}
bool insertAtFront(type obj)
{
sPtr<node<type>> temp(new node<type>);
temp->data = obj;
temp->next = head.get();
//For future reference, &*head = head.get()
head = temp;
//delete temp;
size++;
return true;
}
type goToFromFront(int index)
{
sPtr<node<type>> temp = head;
for(int i = 0; i < index; i++)
{
temp = temp->next;
if(temp->next == NULL)
return temp->data;
}
return temp->data;
}
};
smartPointer.h:
#pragma once
class referenceCount
{
private:
int count;
public:
void add()
{
count++;
}
int release()
{
return --count;
}
};
//for non-learning purposes, boost has a good smart pointer
template <class type>
class sPtr
{
private:
type *p;
referenceCount *r;
public:
sPtr()
{
p = NULL;
r = new referenceCount();
r->add();
}
sPtr(type *pValue)
{
p = pValue;
r = new referenceCount();
r->add();
}
sPtr(const sPtr<type> & sp)
{
p = sp.p;
r = sp.r;
r->add();
}
~sPtr()
{
if(r->release() == 0)
{
delete p;
delete r;
}
}
type* get()
{
return p;
}
type& operator*()
{
return *p;
}
type* operator->()
{
return p;
}
sPtr<type>& operator=(const sPtr<type>& sp)
{
if (this != &sp) //self assignment
{
/*if(r->release() == 0)
{
delete p;
delete r;
}*/ //this will cause an error when you take something with no references and set it equal to something
p = sp.p;
r = sp.r;
r->add();
}
return *this;
}
};
node.h:
#pragma once
template <class type>
struct node
{
type data;
node *next;
node()
{
next = NULL;
}
};
The line that specifically throws "Cannot read from 0xfdfdfe01" from the if statement in the linked list's goToFromFront(int), where, at the point j = 2 in the main loop the error is thrown. Upon looking at the MSVS2010 debugger, temp->next is unknown (CXX0030: error, expression cannot be evaluated), which to me seems like it should translate to null, but the expression is throwing a cannot be read error first.
I'm not honestly sure what I've done wrong, and as this is all a learning process for me, any critique is highly appreciated. Thanks in advance!
These should fix your issues:
uncomment code in operator= of sPtr or use swap idiom:
sPtr<type>& operator=(const sPtr<type>& rhs)
{
if (this != &rhs) // self assignment
{
sPtr<type> tmp(rhs);
std::swap(this->p, tmp.p);
std::swap(this->r, tmp.r);
}
return *this;
}
template <class T>
class node
{
public:
T data;
sPtr<node<T> > next;
};
bool insertAtFront(type obj)
{
sPtr<node<type>> temp(new node<type>);
temp->data = obj;
temp->next = head;
head = temp;
size++;
return true;
}
in goToFromFront, 'temp = temp->next;' created a refCount with one usage of temp->next.
when 'temp' goes out of scope, it destroys its content, and so the 'head->next' points to garbage.
When you do sPtr > = T* , you create a temporary object implicitly
you may declare as sTtr constructor as:
explicit sPtr(type *pValue)