ALright, pardon my messy code please. Below is my queue class.
#include <iostream>
using namespace std;
#ifndef QUEUE
#define QUEUE
/*----------------------------------------------------------------------------
Student Class
# Methods #
Student() // default constructor
Student(string, int) // constructor
display() // out puts a student
# Data Members #
Name // string name
Id // int id
----------------------------------------------------------------------------*/
class Student {
public:
Student() { }
Student(string iname, int iid) {
name = iname;
id = iid;
}
void display(ostream &out) const {
out << "Student Name: " << name << "\tStudent Id: " << id
<< "\tAddress: " << this << endl;
}
private:
string name;
int id;
};
// define a typedef of a pointer to a student.
typedef Student * StudentPointer;
template <typename T>
class Queue
{
public:
/*------------------------------------------------------------------------
Queue Default Constructor
Preconditions: none
Postconditions: assigns default values for front and back to 0
description: constructs a default empty Queue.
------------------------------------------------------------------------*/
Queue() : myFront(0), myBack(0) {}
/*------------------------------------------------------------------------
Copy Constructor
Preconditions: requres a reference to a value for which you are copying
Postconditions: assigns a copy to the parent Queue.
description: Copys a queue and assigns it to the parent Queue.
------------------------------------------------------------------------*/
Queue(const T & q) {
myFront = myBack = 0;
if(!q.empty()) {
// copy the first node
myFront = myBack = new Node(q.front());
NodePointer qPtr = q.myFront->next;
while(qPtr != NULL) {
myBack->next = new Node(qPtr->data);
myBack = myBack->next;
qPtr = qPtr->next;
}
}
}
/*------------------------------------------------------------------------
Destructor
Preconditions: none
Postconditions: deallocates the dynamic memory for the Queue
description: deletes the memory stored for a Queue.
------------------------------------------------------------------------*/
~Queue() {
NodePointer prev = myFront, ptr;
while(prev != NULL) {
ptr = prev->next;
delete prev;
prev = ptr;
}
}
/*------------------------------------------------------------------------
Empty()
Preconditions: none
Postconditions: returns a boolean value.
description: returns true/false based on if the queue is empty or full.
------------------------------------------------------------------------*/
bool empty() const {
return (myFront == NULL);
}
/*------------------------------------------------------------------------
Enqueue
Preconditions: requires a constant reference
Postconditions: allocates memory and appends a value at the end of a queue
description:
------------------------------------------------------------------------*/
void enqueue(const T & value) {
NodePointer newNodePtr = new Node(value);
if(empty()) {
myFront = myBack = newNodePtr;
newNodePtr->next = NULL;
} else {
myBack->next = newNodePtr;
myBack = newNodePtr;
newNodePtr->next = NULL;
}
}
/*------------------------------------------------------------------------
Display
Preconditions: requires a reference of type ostream
Postconditions: returns the ostream value (for chaining)
description: outputs the contents of a queue.
------------------------------------------------------------------------*/
void display(ostream & out) const {
NodePointer ptr;
ptr = myFront;
while(ptr != NULL) {
out << ptr->data << " ";
ptr = ptr->next;
}
out << endl;
}
/*------------------------------------------------------------------------
Front
Preconditions: none
Postconditions: returns a value of type T
description: returns the first value in the parent Queue.
------------------------------------------------------------------------*/
T front() const {
if ( !empty() )
return (myFront->data);
else
{
cerr << "*** Queue is empty -- returning garbage value ***\n";
T * temp = new(T);
T garbage = * temp;
delete temp;
return garbage;
}
}
/*------------------------------------------------------------------------
Dequeue
Preconditions: none
Postconditions: removes the first value in a queue
------------------------------------------------------------------------*/
void dequeue() {
if ( !empty() ) {
NodePointer ptr = myFront;
myFront = myFront->next;
delete ptr;
if(myFront == NULL)
myBack = NULL;
} else {
cerr << "*** Queue is empty -- "
"can't remove a value ***\n";
exit(1);
}
}
/*------------------------------------------------------------------------
pverloaded = operator
Preconditions: requires a constant reference
Postconditions: returns a const type T
description: this allows assigning of queues to queues
------------------------------------------------------------------------*/
Queue<T> & operator=(const T &q) {
// make sure we arent reassigning ourself
// e.g. thisQueue = thisQueue.
if(this != &q) {
this->~Queue();
if(q.empty()) {
myFront = myBack = NULL;
} else {
myFront = myBack = new Node(q.front());
NodePointer qPtr = q.myFront->next;
while(qPtr != NULL) {
myBack->next = new Node(qPtr->data);
myBack = myBack->next;
qPtr = qPtr->next;
}
}
}
return *this;
}
private:
class Node {
public:
T data;
Node * next;
Node(T value, Node * first = 0) : data(value),
next(first) {}
};
typedef Node * NodePointer;
NodePointer myFront,
myBack,
queueSize;
};
/*------------------------------------------------------------------------
join
Preconditions: requires 2 queue values
Postconditions: appends queue2 to the end of queue1
description: this function joins 2 queues into 1.
------------------------------------------------------------------------*/
template <typename T>
Queue<T> join(Queue<T> q1, Queue<T> q2) {
Queue<T> q1Copy(q1), q2Copy(q2);
Queue<T> jQueue;
while(!q1Copy.empty()) {
jQueue.enqueue(q1Copy.front());
q1Copy.dequeue();
}
while(!q2Copy.empty()) {
jQueue.enqueue(q2Copy.front());
q2Copy.dequeue();
}
cout << jQueue << endl;
return jQueue;
}
/*----------------------------------------------------------------------------
Overloaded << operator
Preconditions: requires a constant reference and a Queue of type T
Postconditions: returns the ostream (for chaining)
description: this function is overloaded for outputing a queue with <<
----------------------------------------------------------------------------*/
template <typename T>
ostream & operator<<(ostream &out, Queue<T> &s) {
s.display(out);
return out;
}
/*----------------------------------------------------------------------------
Overloaded << operator
Preconditions: requires a constant reference and a reference of type Student
Postconditions: none
description: this function is overloaded for outputing an object of type
Student.
----------------------------------------------------------------------------*/
ostream & operator<<(ostream &out, Student &s) {
s.display(out);
}
/*----------------------------------------------------------------------------
Overloaded << operator
Preconditions: requires a constant reference and a reference of a pointer to
a Student object.
Postconditions: none
description: this function is overloaded for outputing pointers to Students
----------------------------------------------------------------------------*/
ostream & operator<<(ostream &out, StudentPointer &s) {
s->display(out);
}
#endif
Now I'm having some issues with it. For one, when I add 0 to a queue and then I output the queue like so..
Queue<double> qdub;
qdub.enqueue(0);
cout << qdub << endl;
That works, it will output 0. But for example, if I modify that queue in any way.. like.. assign it to a different queue..
Queue<double> qdub1;
Queue<double> qdub2;
qdub1.enqueue(0;
qdub2 = qdub1;
cout << qdub2 << endl;
It will give me weird values for 0 like.. 7.86914e-316.
Help on this would be much appreciated!
Your haven't defined a copy constructor or an assignment operator. The ones you have take an instance of the queued type, not another queue. For assigning and copying queues themselves, the compiler will still use the automatically generated ones which do the wrong thing.
(This probably doesn't explain the output of that particular snippet.)
Another thing that is completely wrong (even though, again, the snippet never invokes this function or you'd get compiler errors all over the place):
Queue<T> & operator=(const T &q) {
// make sure we arent reassigning ourself
// e.g. thisQueue = thisQueue.
if(this != &q) {
this->~Queue();
Calling destructor explicitly like that, and then going on to use the instance is not allowed. Explicit destructor calls only go hand in hand with constructing objects with placement new.
operator= is normally implemented in terms of copy constructor and a swap method (which swaps the internal representation between two instances):
void swap(Queue<T>& rhv)
{
std::swap(myFront, rhv.myFront);
std::swap(myBack, rhv.myBack);
std::swap(queueSize, rhv.queueSize);
}
Queue<T>& operator=(const Queue<T>& rhv)
{
Queue<T> copy(rhv);
this->swap(copy);
} //the destructor of copy releases the previous contents of *this
I don't see an assignment operator there, which means you're getting the compiler generated default, which will do a shallow copy. You probably need to supply your own to do a deep copy instead. What your comments call a copy ctor isn't really a copy ctor either. A copy ctor always takes a const reference to the object being copied, so the signature would be:
Queue(Queue const &original);.
You need a proper assignment operator. Your example would probably not compile the way you provided your class.
Even if I am wrong, the main mistake in your code is that your operator= calls it's own destructor. This is horribly wrong. The destructor will later called 'naturally' on as well. This means that your objects will be deleted twice. (Because you don't assign NULL to Queue.myFront in your destructor.)
Don't manually call destructors.
For a basic exercise, I recommend that you place a breakpoint on the line qdub2 = qdub1 and then debug step by step to see what your code really does.
According to general coding standard you should not call
this->~Queue()
through this statement a object is trying to delete itself.
try to copy data into new queue and then delete it if it goes out of scope. otherwise keep it as it is.
another example for understanding C++ template
Related
I am trying to understand move semantics and in particular how std::move() works.
I understood that it's basically a static-cast to an rvalue reference type, but this exercise gets me confused. I have implemented a Node class following the Rule of Five (I know I could have followed the copy and swap idiom for a better implementation).
class Node
{
public:
Node(char data = ' ', Node *left_child = NULL, Node *right_child = NULL) : _data(data), _left_child(left_child), _right_child(right_child)
{
std::cout << "NODE CONSTRUCTOR" << std::endl;
}
Node(const Node& node);
Node(Node&& node) noexcept;
GetData() const;
Node& operator=(const Node &n);
Node& operator=(Node&& node) noexcept;
~Node();
protected:
Node *_left_child;
Node *_right_child;
char _data;
};
char Node::GetData() const
{
return _data;
}
Node::Node(const Node& node)
{
...
}
Node::Node(Node&& node) noexcept
{
std::cout << "MOVE CONSTRUCTOR" << std::endl;
this->_data = node.GetData();
this->_left_child = node._left_child;
this->_right_child = node._right_child;
node._right_child = nullptr;
node._left_child = nullptr;
}
Node& Node::operator=(Node&& node) noexcept
{
std::cout << "MOVE ASSIGNMENT OPERATOR " << std::endl;
if(&node != this)
{
if(this->_right_child != nullptr)
{
delete this->_right_child;
}
if(this->_left_child != nullptr)
{
delete this->_left_child ;
}
}
this->_data = node.GetData();
this->_left_child = node._left_child;
this->_right_child = node._right_child;
node._right_child = nullptr;
node._left_child = nullptr;
return *this;
}
Node::~Node()
{
delete _left_child;
delete _right_child;
}
Node& Node::operator=(const Node &n)
{
...
}
Then in my main() function:
int main() {
Node *NodeOne = new Node{};
Node NodeTwo{};
std::stack<Node*> stack_of_nodes_ptr;
stack_of_nodes_ptr.push(std::move(NodeOne));
delete stack_of_nodes_ptr.top();
stack_of_nodes_ptr.pop();
std::stack<Node> stack_of_nodes;
stack_of_nodes.push(std::move(NodeTwo));
return 0;
}
The output is:
NODE CONSTRUCTOR
NODE CONSTRUCTOR
CALLING NODE BASE DESTRUCTOR
MOVE CONSTRUCTOR
CALLING NODE BASE DESTRUCTOR
CALLING NODE BASE DESTRUCTOR
My doubt arises seeing that the move constructor is not called in the first push_back() but only in the second one. The only difference here is that the first stack is of Node* pointers while the other one is a stack of Node objects.
Could you please tell me why, in case of raw pointer, move constructor is not called?
Could you please tell me why in case of raw pointer std::move is not called?
std::move is called. But std::move doesn't print anything. Remember that std::move is:
basically a static cast to an rvalue reference type
Calling std::move never causes any output.
My doubt arises seeing that the move constructor is not called in the first push_back
You didn't move an object of type Node, so the move constructor of Node was not called.
For all fundamental types, moving is same as copying. Pointers are fundamental types.
So i have a Linked list implementation of my own and it can successfully keep integers and call them when needed with overloaded [] operator but when it comes to storing a class in my linked list, it seems that i can't call the class appropriately (using the same [] operator).
Called functions and members of my Linked List;
#include <iostream>
#include <assert.h>
template<typename T>
struct node {
T data;
node<T>* next;
};
template<typename T>
class Vectem {
private:
node<T>* head;
node<T>* last;
int lenght;
public:
void insert(T value) {
last->next = new node<T>;
last = last->next;
last->data = value;
last->next = NULL;
if (isEmpty()) {
head = last;
}
lenght++;
}
node<T>* search(int indx) {
node<T>* current;
current = head;
int count=0;
while (current != NULL) {
if (count == indx) {
break;
}
current = current->next;
count++;
}
return current;
}
T& operator [](int indx) {
assert(indx >= lenght - 1);
T result;
result = search(indx)->data;
return result;
}
};
And here is the main function and the class that i try to store;
#include <iostream>
#include <fstream>
#include <string>
#include "VectemLibrary.h"
class word {
public:
std::string value;
int count;
word(std::string value, int count): value(value),count(count) {
}
word() {
value = "NOT ASSIGNED";
count = 0;
}
word(const word& w1) {
value = w1.value;
count = w1.count;
}
~word() {
std::cout << "Word Destroyed" << std::endl;
}
};
int main()
{
Vectem<word> wordContainer;
word newWord("hello", 1);
wordContainer.insert(newWord);
std::cout << wordContainer[0].value;
}
Visual studio gave me the expection with this message at the last line where i call the first member of linked list with [];
Exception thrown at 0x7A0CF3BE (ucrtbased.dll) in Top 10 words.exe: 0xC0000005: Access violation reading location 0xCCCCCCCC.
I think that my lack of experience with pointers may have caused the problem but if you see something that i can't, Please enlighten me.
There are other problems with the code you posted as well (e.g. isEmpty() is not declared or defined), but I'll focus on the issue you explicitly mentioned.
In your operator:
T& operator [](int indx) {
assert(indx >= lenght - 1);
// You declare this variable on the stack
T result;
result = search(indx)->data;
// And then you return this variable by reference; this is not okay
return result;
}
As mentioned in my code comments (and by #Johnny Mopp in his comment to your post), you shouldn't (can't) return a reference or pointer to a variable declared within the returning function and constructed on the stack. Anything on the stack will be destroyed once the function call ends, so any returned pointers or references to such variables will be dangling references; using said pointers or references will result in undefined behavior.
So you don't want to return a reference to a stack-allocated variable like result; you want to return a reference to the data within the node itself (which is allocated on the heap by insert()), as it will still be a valid reference after the function returns:
return search(indx)->data;
There are several problems with your code, but the most important is that you are not initializing the head, last, or lenght members of Vectem at all. An Access Violation error at address 0xCCCCCCCC is a good indication that uninitialized memory is being accessed, as some compilers/setups fill uninitialized memory with 0xCC bytes, thus head and last are initially 0xCCCCCCCC in your case.
You need to add appropriate constructors to Vectem (as well as a destructor, a copy constructor, and a copy assignment operator, per the Rule of 3), eg:
template<typename T>
class Vectem {
private:
node<T>* head;
node<T>* last;
int lenght;
public:
Vectem() : head(NULL), last(NULL), lenght(0) {}
Vectem(const Vectem &src) : head(NULL), last(NULL), lenght(0)
{
// copy src's data to *this as needed ...
}
~Vectem()
{
// cleanup *this as needed ...
}
Vectem& operator=(const Vectem &rhs)
{
if (&rhs != this) {
// clear *this, and copy rhs's data to *this, as needed ...
}
return *this;
}
...
};
Or, in C++11 and later, you can initialize the members directly in their declarations (also, be sure to add a move constructor and a move assignment operator, per the Rule of 5), eg:
template<typename T>
class Vectem {
private:
node<T>* head = nullptr;
node<T>* last = nullptr;
int lenght = 0;
public:
Vectem() = default;
Vectem(const Vectem &src)
{
// copy src's data to *this as needed ...
}
Vectem(Vectem &&src) : head(src.head), last(src.last), lenght(src.lenght)
{
src.head = nullptr;
src.last = nullptr;
src.lenght = 0;
}
~Vectem()
{
// cleanup *this as needed ...
}
Vectem& operator=(const Vectem &rhs)
{
if (&rhs != this) {
// clear *this, and copy rhs's data to *this, as needed ...
}
return *this;
}
Vectem& operator=(Vectem &&rhs)
{
// clear *this as needed...
head = rhs.head; rhs.head = nullptr;
last = rhs.last; rhs.last = nullptr;
lenght = rhs.lenght; rhs.lenght = 0;
return *this;
}
...
};
That being said, insert() is also buggy, as it is dereferencing last before checking that last is actually pointing at a valid node. Try something more like this instead:
void insert(T value) {
node<T> *n = new node<T>{value, NULL};
if (!head) head = n;
if (last) last->next = n;
last = n;
++lenght;
}
Alternatively:
void insert(T value) {
node<T> **p = (last) ? &(last->next) : &head;
*p = new node<T>{value, NULL};
last = *p;
++lenght;
}
I would be very grateful for some help. In my computer science class, we're being asked to do something I've never done before, and I don't understand my problem well enough to even know what terms to Google.
We have three files. lists.h, lists.cpp and driver.cpp
lists.h - this was provided by the professor and CANNOT be altered by me. It's the base class from which I will derive a new class in...
lists.cpp - Here I implement and doubly-linked list in class DLList. I've done dll before, but not this way. So you'll see a lot of code here despite me not being able to test any of it. Don't worry if my functions are wrong here, I'm simply trying to create a doubly linked list in ...
driver.cpp - this is the file I'll be using to test my functions in class DLList.
So anyway, I compile and get ....
g++ -c -g -Wall -std=c++11 driver.cpp
driver.cpp: In function ‘int main()’:
driver.cpp:12:5: error: ‘DLList’ was not declared in this scope
DLList<int> mylist;
^
I understand the error. I've seen this before when a function/class/etc is not being seen by main. In simpler code, it is because it is after main. But here, I just don't know how to fix it. Obviously, driver.cpp cannot see my code in lists.cpp.
Here is my code --
the unalterable lists.h
template<typename E> class List {
private:
void operator =(const List&) {} // Protect assignment
List(const List&) {} // Protect copy constructor
public:
List() {} // Default constructor
virtual ~List() {} // Base destructor
// Clear contents from the list, freeing memory
virtual void clear() = 0;
// Insert an element at the beginning of the list.
virtual void prepend(const E& item) = 0;
// Append an element at the end of the list.
virtual void append(const E& item) = 0;
// Extra credit: Insert an element at the current location, if possible;
// return true if successful, false if there is no current element
virtual bool insert(const E& item) = 0;
// Extra credit: Remove and assign to item the current element, if possible;
// return true if successful, false if there is no current element
virtual bool remove(E& item) = 0;
// Set the current position to the first element of the list, if possible;
// return true if successful, false if list was empty
virtual bool moveToStart() = 0;
// Set the current position to the last element of the list, if possible;
// return true if successful, false if list was empty
virtual bool moveToEnd() = 0;
// Move the current position one step right, if possible;
// return true if successful, false if already at the end
virtual bool next() = 0;
// Move the current position one step left, if possible;
// return true if successful, false if already at the beginning
virtual bool prev() = 0;
// Return a pointer to the current element (or NULL if none)
virtual const E* getValue() const = 0;
// Return total number of active nodes
virtual int numActive() = 0;
// Return total number of free nodes
virtual int numFree() = 0;
};
// Factory function
template<typename E> List<E> *createList();
lists.cpp
#include "lists.h"
#include <cstddef>
#include <iostream>
using namespace std;
// Doubly linked list link node with freelist support
template <typename E> class Link {
private:
// required by Lab 4
static int free; // # of nodes free
static int active; // # of nodes in use
static Link<E> *freelist; // Reference to freelist head
E element; // Value for this node
Link *next; // Pointer to next node in list
Link *prev; // Pointer to previous node
public:
// Constructors
Link(const E& it, Link *prevp=NULL, Link *nextp=NULL) {
element = it;
prev = prevp;
next = nextp;
}
Link(Link *prevp =NULL, Link *nextp =NULL) {
prev = prevp;
next = nextp;
}
void * operator new(std::size_t) { // Overloaded new operator
active++; // add to active count
if (freelist == NULL) { // Create space
return ::new Link; // ::new means use the standard c++ new operator
}
Link<E> *temp = freelist; // Can take from freelist
freelist = freelist->next;
free--; // will only subtract if we take from freelist
return temp; // Return the link
}
// Overloaded delete operator
void operator delete(void* ptr) {
free++;
active--;
// eliminate the Link being deleted from the active list
Link *prev_tmp=((Link<E>*)ptr)->prev;
Link *next_tmp=((Link<E>*)ptr)->next;
prev_tmp->next=next_tmp;
next_tmp->prev=prev_tmp;
((Link<E>*)ptr)->next = freelist; // Attach deleted Link to the head of the freelist
freelist = (Link<E>*)ptr; // Now redefine the freelist to the new head
}
E get_data() const {
return element;
}
E set_data(E& it) {
element=it;
}
Link<E> *get_next() const {
return next;
}
Link<E> *get_ptrb() const {
return prev;
}
void set_next(Link<E> *new_next ) {
next = new_next;
}
void set_prev(Link<E> *new_prev) {
prev = new_prev;
}
int get_free() {
return free;
}
int get_active(){
return active;
}
};
// The freelist head pointer is actually created here
template <typename E>
Link<E> *Link<E>::freelist = NULL;
template <typename E> class DLList: public List<E> {
private:
Link<E> *head; // Pointer to list header
Link<E> *tail; // Pointer to last element
Link<E> *curr; // Access to current element
void operator =(const DLList&) {} // Protect assignment
DLList(const DLList&) {} // Protect copy constructor
public:
// Default constructor
DLList() {
head=NULL;
tail=NULL;
}
// Base destructor
~DLList() {
//delete
}
// Clear contents from the DLList, freeing memory
void clear() = 0;
// Insert an element at the beginning of the DLList.
void prepend(const E& item) {
Link<E> *newLink = new Link<E>(item);
if (head==NULL) {
head=newLink;
tail=newLink;
curr=newLink;
}
else {
newLink->set_next(head);
head=newLink;
curr=newLink;
}
}
// Append an element at the end of the DLList.
void append(const E& item) {
Link<E> *newLink = new Link<E>(item);
if (head==NULL) {
head=newLink;
tail=newLink;
curr=newLink;
}
else {
tail->set_next(newLink);
tail=newLink;
curr=newLink;
}
}
void print_list() {
if (head==NULL) {
cout << "EMPTY LIST" << endl;
}
else {
Link<E> *temp_ptr = head;
int index=0;
while(temp_ptr) {
cout << "Link " << index++ << ": " << temp_ptr->get_data() << endl;
temp_ptr = temp_ptr->get_next();
}
}
}
// Extra credit: Insert an element at the current location, if possible;
// return true if successful, false if there is no current element
bool insert(const E& item) {
if (curr==NULL) {
return false;
}
else {
Link<E> *newLink = new Link<E>(item);
Link<E> *prev_ptr=curr->get_prev;
Link<E> *next_ptr=curr->get_next();
prev_ptr->set_next(curr);
curr->set_prev(prev_ptr);
next_ptr->set_prev(curr);
curr->set_next(next_ptr);
return true;
}
}
// Extra credit: Remove and assign to item the current element, if possible;
// return true if successful, false if there is no current element
bool remove(E& item) {
if (curr==NULL) {
return false;
}
else {
curr->set_data(item);
}
}
// Set the current position to the first element of the DLList, if possible;
// return true if successful, false if DLList was empty
bool moveToStart() {
if (head==NULL) {
return false;
}
else {
curr=head;
return true;
}
}
// Set the current position to the last element of the DLList, if possible;
// return true if successful, false if DLList was empty
bool moveToEnd() {
if (head==NULL) {
return false;
}
else {
curr=tail;
return true;
}
}
// Move the current position one step right, if possible;
// return true if successful, false if already at the end
bool next() {
if (curr==tail) {
return false;
}
else {
curr=curr->get_next();
return true;
}
}
// Move the current position one step left, if possible;
// return true if successful, false if already at the beginning
bool prev() {
if (curr==head) {
return false;
}
else {
curr=curr->get_prev();
return true;
}
}
// Return a pointer to the current element (or NULL if none)
const E* getValue() {
if (curr==NULL) {
return NULL;
}
else {
curr->get_data();
}
}
// ******** MIGHT HAVE TO GET THIS DATA FROM MULTIPLE SOURCES IF THE PTR IS NULL!!
// BUG !
// Return total number of active nodes
int numActive() {
return curr->get_active();
}
// ******** MIGHT HAVE TO GET THIS DATA FROM MULTIPLE SOURCES IF THE PTR IS NULL!!
// BUG !
// Return total number of free nodes
int numFree() {
return curr->get_free();
}
};
// Explicit instantiation
template List<int> *createList();
driver.cpp
#include <iostream>
#include "lists.h"
using namespace std;
void uppercaseify(string& mystr) {
for (auto& c: mystr)
c = toupper(c);
}
int main() {
createList<int>();
DLList<int> mylist;
return 0;
}
I think you are not supposed to explicitly instantiate your DLList class in main(). This can't work because you don't have the declaration of it available in "driver.cpp".
What you should do instead is implement the factory function in "list.cpp" to return a dynamically allocated instance of your DLList:
template<> List<int> *createList() { return new DLList<int>; }
So the call to createList<int>() in "driver.cpp" will then create an instance of your DLList which you can test through the interface of List:
int main() {
// Create a DLList through factory function.
List<int>* list = createList<int>();
// Use the DLList through the List interface.
list->append( ... );
// Finished with using list, free the memory
delete list; list = nullptr;
// Not necessary - we have created the DLList through factory function!
// DLList<int> mylist;
return 0;
}
Well you're right, the error is there because there is no DLList type declared in your driver file. The easiest option to fix it would be to include your list.cpp file into your driver file
#include "list.cpp"
Generally when you're working with a .h and a .cpp file that have the same name they should refer to the same class. So if you were writing this example outside of a class exercise you would probably name your list.cpp file DLList.h (note that template classes should be in a .h file).
I have troubles with the pointers using my assignment opperator, it doesn't make a new qeueu, instead the new array points to the old one. So when I delete in the new queue the values in my old queue changes.
First off all I can see that my copy constructor isn't called in my main for some unknown reason, the problem is probably related with that.
Some of my main code used to illustrate the problem:
aQueue.enqueue(10);
aQueue.enqueue(20);
Queue<int> cQueue = aQueue;
cout << "aQueue: "; aQueue.printQeueue(2, 0);
cout << "cQueue: "; cQueue.printQeueue(3, 0);
cQueue.dequeue();
cout << "aQueue: "; aQueue.printQeueue(4, 1);
cout << "cQueue: "; cQueue.printQeueue(5, 1);
system("pause 4");
This is where the problems start, if I enqueue aQueue with 10 and 20 and then assign cQueue to aQueue, if I print aQueue the result is: 10 20. After that dequeue cQueue and print aQueue the result is: -179016023. If I print cQueue the result is: 20, as it should be.
The output: http://imgur.com/XBaSXAT
Here follows the functions used direct or indirect:
template <typename T>
T Queue<T>::dequeue(){
T temp = front();
Node *old = fronten;
fronten = fronten->next;
delete old;
return temp;
}
template <typename T>
Queue<T>::Queue(const T &rhs){
Node *tempfront = rhs.fronten;
while (tempfront.fronten!=rhs.back){
enqueue(tempfront);
tempfront = tempfront->next;
}
}
template <typename T>
void Queue<T>::enqueue(const T& item){
if (isEmpty()){
back = fronten = new Node(item);
}
else
back = back->next = new Node(item);
}
Node(const T &theElement, Node *n = nullptr): element(theElement), next(n) {};
You don't have at the moment copy constructor for your Queue class (or you don't show it). Yours
template <typename T> Queue<T>::Queue(const T &rhs)
is constructor for Queue from the type it stores. You need something like:
template <class T>
class Queue
{
public:
Queue( const Queue &); // copy ctor
Queue& operator=( const Queue& q); // assignment operator
//...
};
I am having some trouble with my homework and could use your help.
I am getting some sort of error when I try to run my program. When i compile it i get the success mssage but when i try to run it i get a popup with the error "Unhandled exception at 0x011b18d2 in Project 2.exe: 0xC0000005: Access violation reading location 0xccccccd0." If anyone can help me i would appreciate it, thank you.
This is the code i was assigned to build on (this cannot be changed)
#include <iostream >
#include "stack.h"
using namespace std ;
int main ()
{
Stack < int > s1 , s2 ;
int element ;
s1 . push (1); s1 . push (2); s1 . push (3);
s1 . pop ( element );
cout << " s1 popped element : " << element << endl ;
s2 = s1 ;
s2 . push (4);
s2 . pop ( element );
cout << " s2 popped element : " << element << endl ;
s1 . pop ( element );
cout << " s1 popped element : " << element << endl ;
s2 . makeEmpty ();
s2 . isEmpty () ? cout << " s2 is empty \n": cout << " s2 is not empty \n ";
system ("pause");
return 0;
}
This is what i wrote to compliment the code above
template <class DataType>
struct Node{
DataType info;
Node<DataType>*next;
};
template <class DataType>
class Stack
{
public:
Stack();
void push(DataType elementToPush);
bool pop(DataType & poppedElement);
bool peek(DataType & topElement);
Stack(const Stack<DataType> &element); // Copy constructor
~Stack(); // Destructor
Stack<DataType> & operator=(const Stack<DataType> &element); //Overload assignment operator
bool isEmpty()const;
void makeEmpty();
private:
Node<DataType>*top;
Node<DataType>*header;
inline void deepCopy(const Stack<DataType> & original);
};
template<class DataType>
Stack<DataType>::Stack()
{
Node<DataType>*top=new Node<DataType>;
}
template<class DataType> // Remove the node at the front of the list and return the element
bool Stack<DataType>::pop(DataType & poppedElement)
{
Node<DataType>*ptr=top;
ptr=ptr->next;
Node<DataType>*ptr2=ptr->next;
top->next=ptr2;
poppedElement = ptr->info;
delete ptr;
return true;
}
template<class DataType> // Return the element at the front of the list wothout deleting it
bool Stack<DataType>::peek(DataType & topElement)
{
if(top->next==NULL)
return false;
topElement=top->next->info;
return true;
}
template<class DataType> // Make a new node for the element and push it to the front of the list
void Stack<DataType>::push(DataType elementToPush)
{
Node<DataType>*ptr=top;
Node<DataType>*ptr2=new Node<DataType>;
ptr2->info=elementToPush;
ptr2->next=ptr->next;
ptr->next=ptr2;
}
template<class DataType> // Check to see if the list is empty
bool Stack<DataType>::isEmpty()const
{
return top->next==NULL;
}
template<class DataType> // Empry the list out
void Stack<DataType>::makeEmpty()
{
Node<DataType>*ptr=top;
while(top->next != NULL)
{
while(ptr->next != NULL)
ptr->next;
delete ptr->next;
}
}
template<class DataType> // Deep copy
inline void Stack<DataType>::deepCopy(const Stack<DataType> & original)
{
Node<DataType>*copyptr=new Node<DataType>;
Node<DataType>*originalptr=top;
while(originalptr != NULL)
{
originalptr=originalptr->next;
copyptr->next=new Node<DataType>;
copyptr->info=originalptr->info;
}
}
template<class DataType> // Copy Constructor
Stack<DataType>::Stack(const Stack<DataType> &element)
{
deepCopy(element);
}
template<class DataType> // Destructor
Stack<DataType>::~Stack()
{
makeEmpty();
}
template<class DataType> // Overload assignment operator
Stack<DataType> & Stack<DataType>::operator=(const Stack<DataType> &element)
{
if(this == &element)
return *this;
makeEmpty();
deepCopy(element);
return *this;
}
I got pushback on my previous answer. Maybe this one will be better received. If you don't like my choice of white space, that is what pretty-printers are for. The code below is the original code reformatted. My thoughts are included as interlinear gloss.
Node is an implementation detail of your Stack. It should be scoped as a private type declaration, putting here pollutes the namespace. Also, if this class had a constructor that either initialized next to nullptr or required it to be set explicitly, some bugs, such as the one you found, would be easier to diagnose. As it stands, after Node is constructed, next can point to a random memory location.
template <class DataType>
struct Node {
DataType info;
Consider using a smart pointer here.
Node<DataType>* next; };
template <class DataType>
class Stack {
public:
Stack();
The argument should be const& to avoid extra copying.
void push(DataType elementToPush);
bool pop(DataType& poppedElement);
This can be a const method.
bool peek(DataType& topElement);
element is a poor name. The copy constructor copies an entire stack, not just an element.
Stack(const Stack<DataType>& element); // Copy constructor
~Stack(); // Destructor
Stack<DataType>& operator=(const Stack<DataType>&
element); //Overload assignment operator
bool isEmpty() const;
void makeEmpty();
private:
Consider using a smart pointer here.
Node<DataType>* top;
header is not used. It should be deleted.
Node<DataType>* header;
inline void deepCopy(const Stack<DataType>& original); };
template<class DataType>
Stack<DataType>::Stack() {
top should be initialized to nullptr in a member initialization list. The empty node you
are using here is not required, it makes you code more complex, and you end up leaking it later.
Also, this is a major bug. You are assigning to a local here, not the member variable!
Node<DataType>* top = new Node<DataType>; }
template<class DataType> // Remove the node at the front of the list and return the element
bool Stack<DataType>::pop(DataType& poppedElement) {
If you want ptr to be top->next just say that.
Node<DataType>* ptr = top;
ptr = ptr->next;
This ptr2 variable is not needed. You just need top->next = top->next->next. Also note that the empty head element is adding noise here.
Node<DataType>* ptr2 = ptr->next;
top->next = ptr2;
poppedElement = ptr->info;
delete ptr;
You need to have tested for underflow to return false in that case.
return true; }
People are pretty forgiving about comments, but it is best if they are properly spelled and punctuated.
template<class DataType> // Return the element at the front of the list wothout deleting it
bool Stack<DataType>::peek(DataType& topElement) {
if (top->next == NULL) {
return false; }
topElement = top->next->info;
return true; }
template<class DataType> // Make a new node for the element and push it to the front of the list
void Stack<DataType>::push(DataType elementToPush) {
This variable is meaningless, just use top.
Node<DataType>* ptr = top;
ptr2 can be constructed with the values you need instead of being mutated afterwards. Try auto ptr2 = new Node<DataType> { elementToPush, ptr->next };. Also, consider using a smart pointer.
Node<DataType>* ptr2 = new Node<DataType>;
ptr2->info = elementToPush;
ptr2->next = ptr->next;
ptr->next = ptr2; }
template<class DataType> // Check to see if the list is empty
bool Stack<DataType>::isEmpty()const {
return top->next == NULL; }
This function is just broken. You need to rethink it.
template<class DataType> // Empry the list out
void Stack<DataType>::makeEmpty() {
Node<DataType>* ptr = top;
while (top->next != NULL) {
One while loop will do you. Lists are linear, not square.
while (ptr->next != NULL) {
This statement has no effect; it does nothing. Your compiler should be warning about that, turn on warnings, or turn the warning level up.
ptr->next; }
delete ptr->next; } }
This is very broken too. You need to iterate over two lists, so you need two iterator variables. One iterator is the stuff you are copying and just needs to be bumped along as you read it. The other is mutating the current object and has slightly more book keeping.
template<class DataType> // Deep copy
inline void Stack<DataType>::deepCopy(const Stack<DataType>& original) {
Node<DataType>* copyptr = new Node<DataType>;
Node<DataType>* originalptr = top;
while (originalptr != NULL) {
originalptr = originalptr->next;
copyptr->next = new Node<DataType>;
copyptr->info = originalptr->info; } }
template<class DataType> // Copy Constructor
Stack<DataType>::Stack(const Stack<DataType>& element) {
deepCopy(element); }
template<class DataType> // Destructor
Stack<DataType>::~Stack() {
Note that makeEmpty does not delete your empty head node. This will leak a node.
makeEmpty(); }
template<class DataType> // Overload assignment operator
Stack<DataType>& Stack<DataType>::operator=(const Stack<DataType>&
element) {
if (this == &element) {
return *this; }
makeEmpty();
Again, your empty head node is causing pain here. Does deepCopy create the empty head node or not? Your use of it in your copy constructor seems to assume it does. Your use of it here seems to assume it does not. In fact, I think the problem is that makeEmpty does not delete your head node, if it did, both this function and your destructor would work properly.
deepCopy(element);
return *this; }
What you are seeing is a run-time error, not a build error. And your IDE reports a successful build, not your debugger. Your debugger is what allows you to trace through the program line-by-line and inspect the values of your variables.
Compare your code to the following.
template <class DataType>
struct Node {
DataType info;
Node<DataType>* next; };
template <class DataType>
class Stack {
public:
Stack();
void push(DataType elementToPush);
bool pop(DataType& poppedElement);
bool peek(DataType& topElement);
Stack(const Stack<DataType>& element);
~Stack();
Stack<DataType>& operator=(const Stack<DataType>& element);
bool isEmpty()const;
void makeEmpty();
private:
Node<DataType>* top;
inline void deepCopy(const Stack<DataType>& original); };
// Linked list stack implementation.
template<class DataType>
Stack<DataType>::Stack() {
// Head of the list. Not actually used for anything. Why is this here?
top = new Node<DataType>; }
// Remove the node at the front of the list and return the element
// Does not check for underflow.
template<class DataType>
bool Stack<DataType>::pop(DataType& poppedElement) {
Node<DataType>* ptr = top->next;
Node<DataType>* ptr2 = ptr->next;
top->next = ptr2;
poppedElement = ptr->info;
delete ptr;
return true; }
// Return the element at the front of the list without deleting it
template<class DataType>
bool Stack<DataType>::peek(DataType& topElement) {
if (top->next == NULL) {
return false; }
topElement = top->next->info;
return true; }
// Make a new node for the element and push it to the front of the list
template<class DataType>
void Stack<DataType>::push(DataType elementToPush) {
Node<DataType>* ptr2 = new Node<DataType>;
ptr2->info = elementToPush;
ptr2->next = top->next;
top->next = ptr2; }
// Check to see if the list is empty
template<class DataType>
bool Stack<DataType>::isEmpty()const {
return top->next == NULL; }
// Empty the list out
template<class DataType>
void Stack<DataType>::makeEmpty() {
while (top->next != NULL) {
Node<DataType>* ptr = top->next;
top->next = ptr->next;
delete ptr; } }
// Deep copy
template<class DataType>
inline void Stack<DataType>::deepCopy(const Stack<DataType>& original) {
Node<DataType>* origiter = original.top;
Node<DataType>* thisiter = top;
while (origiter->next != NULL) {
thisiter->next = new Node<DataType>(*(origiter->next));
origiter = origiter->next;
thisiter = thisiter->next; }
thisiter->next = NULL; }
// Copy Constructor
template<class DataType>
Stack<DataType>::Stack(const Stack<DataType>& element) {
deepCopy(element); }
// Destructor
template<class DataType>
Stack<DataType>::~Stack() {
// This leaks because the head node is still there.
makeEmpty(); }
// Overload assignment operator
template<class DataType>
Stack<DataType>& Stack<DataType>::operator=(const Stack<DataType>&
element) {
if (this == &element) {
return *this; }
makeEmpty();
deepCopy(element);
return *this; }