Calling a derived class from my driver.cpp - c++

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).

Related

Linked list consist of a class throws exception 0xC0000005

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;
}

return new BinarySearchTree - argument list for class template is missing

We have an assignment to create a Binary Search Tree with some basic functions. I feel I'd be capable of scraping by if it weren't for the files included with the assignment that we need to adhere to in order for the graders to implement our code with their grading program. Students are given a file called "Factory.cpp" which has a function that attempts to return an object of "BinarySearchTree" (return new BinarySearchTree();). However, VS 2013 gives me the error seen in the title. After some research, I can't find any infomration I can implement into my own problem to get rid of the error. Template classes are obviously more abstract and I can't find out what to include/leave out, etc to make things work.
The following is my incomplete code I have so far in my BinarySearchTree.h:
#pragma once
#include "BSTInterface.h"
#include "NodeInterface.h"
#ifndef BINARY_SEARCH_TREE_H
#define BINARY_SEARCH_TREE_H
struct BTNode :public NodeInterface{
// Data Fields
int data;
BTNode* left;
BTNode* right;
// Constructor
BTNode(const int& the_data,
BTNode* left_val = NULL,
BTNode* right_val = NULL) :
data(the_data), left(left_val), right(right_val) {}
// Destructor (to avoid warning message)
virtual ~BTNode() {}
// Interface Functions
int getData(){
return data;
}
NodeInterface* getLeftChild(){
return left;
}
NodeInterface* getRightChild(){
return right;
}
}; // End BTNode
#include <sstream>
template<class T>
class BinarySearchTree:public BSTInterface
{
public:
BTNode* root;
// BST Constructor / Deconstructor
BinarySearchTree() : root(NULL){}
//BinarySearchTree(const int& the_data,
// const BinarySearchTree& left_child = BinarySearchTree(),
// const BinarySearchTree& right_child = BinarySearchTree()) :
// root(new BTNode(the_data, left_child.root, right_child.root)){}
virtual ~BinarySearchTree(){}
// Interface Functions ----------------------
NodeInterface* getRootNode(){
return root;
}
bool add(int data){
return addRec(root, data);
}
bool addRec(BTNode* &x, int data){
if (x == NULL){
if (Search(root, data) == true){
return false;
}
else{
root = GetNewNode(data);
return true;
}
}
if (data == x->data){
return false;
}
if (x != NULL){
if (data < x->data){
return addRec(x->left, data);
}
if (data > x->data){
return addRec(x->right, data);
}
}
}
bool remove(int data){
return false;
}
bool removeRec(BTNode* &x, int data){
return false;
}
void clear(){
}
// ------------------------------------------
// My Functions -----------------------------
BTNode* GetNewNode(int data){
BTNode* newNode = new BTNode();
newNode->data = data;
newNode->left = newNode->right = NULL;
return newNode;
}
bool Search(BTNode* root, int data) {
if (root == NULL) {
return false;
}
else if (root->data == data) {
return true;
}
else if (data < root->data) { // had <= instead
return Search(root->left, data);
}
else if (data > root->data) { // had no "if"
return Search(root->right, data);
}
}
// ------------------------------------------
};
#endif
Which is derived from the following 2 "Interface" files:
NodeInterface.h:
//YOU MAY NOT MODIFY THIS DOCUMENT
#pragma once
#include <iostream>
class NodeInterface {
public:
NodeInterface() {}
virtual ~NodeInterface() {}
/*Returns the data that is stored in this node*/
virtual int getData() = 0;
/*Returns the left child of this node or null if it doesn't have one.*/
virtual NodeInterface * getLeftChild() = 0;
/*Returns the right child of this node or null if it doesn't have one.*/
virtual NodeInterface * getRightChild() = 0;
};
BSTInterface.h
//YOU MAY NOT MODIFY THIS DOCUMENT
#pragma once
#include "NodeInterface.h"
using namespace std;
class BSTInterface {
public:
BSTInterface() {}
virtual ~BSTInterface() {}
//Please note that the class that implements this interface must be made
//of objects which implement the NodeInterface
/*Returns the root node for this tree*/
virtual NodeInterface * getRootNode() = 0;
/*Attempts to add the given int to the BST tree*/
virtual bool add(int data) = 0;
/*Attempts to remove the given int from the BST tree*/
virtual bool remove(int data) = 0;
/*Removes all nodes from the tree, resulting in an empty tree.*/
virtual void clear() = 0;
};
Then they give us "Factory.h" and "Factory.cpp," which I believe they use to grab our BinarySearchTree from in order to grade using their grading program:
Factory.h:
#include "BSTInterface.h"
using namespace std;
/*
WARNING: It is expressly forbidden to modify any part of this document, including its name
*/
class Factory
{
public:
static BSTInterface * getBST();
};
Factory.cpp:
#include "Factory.h"
#include "BinarySearchTree.h"
//You may add #include statements here
/*
You will MODIFY THIS DOCUMENT.
getBST()
Creates and returns an object whose class extends BSTInterface.
This should be an object of a class you have created.
Example: If you made a class called "BinarySearchTree", you might say, "return new BinarySearchTree();".
*/
BSTInterface * Factory::getBST()
{
return new BinarySearchTree();//Modify this line
}
In "Factory.cpp", BinarySearchTree is marked as an error in VS with the message "argument list for class template is missing." How do I fix this? Along with any other errors you see.
Also, how would I declare a new BinarySearchTree object in a main() and call its functions in order to test it?
For that error, in these lines:
template<class T>
class BinarySearchTree:public BSTInterface
{
just get rid of the first line. That line is telling the compiler that you BinarySearchTree class is a template class. But since your class uses an int for data it would seem that is not needed.
I haven't looked at your other code so I won't comment on anything else.

Can anyone help me with the following compilation errors - regarding two implementations of an Array?

Errors:
delimiters.cpp(41): error C2784: 'std::_String_iterator<_Elem,_Traits,_Alloc>
std::operator + (_String_iterator<_Elem,_Traits,_Alloc>::difference_type,std::_String_iterator<_Elem,_Traits,_Alloc>)' : could not deduce template argument for 'std::_String_iterator<_Elem,_Traits,_Alloc>' from 'char'
1> c:\program files (x86)\microsoft visual studio 10.0\vc\include\xstring(434) : see declaration of 'std::operator +'
stacklinked.cpp(20): error C2061: syntax error : identifier 'StackNode'
stacklinked.cpp(28): error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
stacklinked.cpp(28): error C2063: 'StackNode' : not a function
stacklinked.cpp(28): fatal error C1903: unable to recover from previous error(s); stopping compilation
Responsive Code:
#ifndef STACKLINKED_CPP
#define STACKLINKED_CPP
#include <iostream>
#include "StackLinked.h"
//--------------------------------------------------------------------
template <typename DataType>
StackLinked<DataType>::StackNode(const DataType& newDataItem,
StackLinked<DataType>::StackNode* nextPtr)
//::StackNode
// Creates a stack node containing item newDataItem and next pointer
// nextPtr.
: dataItem(newDataItem), next(nextPtr)
{
}
//--------------------------------------------------------------------
template <typename DataType>
StackLinked<DataType>::StackLinked(int maxNumber)
: top(0)
// Creates an empty stack. The parameter maxNumber is provided for
// compatability with the array implementation and is ignored.
{
}
//--------------------------------------------------------------------
template <typename DataType>
StackLinked<DataType>::StackLinked(const StackLinked& other)
// Copy constructor for linked stack
: top( 0 )
{
(void) operator=(other); // Use operator=, ignore return value
/*
// Alternatively, could duplicate essentially all the code from
// operator= and insert below.
if( ! other.isEmpty() ) {
// Copy first node
top = new StackNode(other.top->dataItem, 0);
StackNode *otherTemp = other.top->next;
StackNode *thisTemp=0, *thisPrevious=top;
// Copy rest of nodes
while( otherTemp != 0 )
{
thisTemp = new StackNode(otherTemp->dataItem, 0);
thisPrevious->next = thisTemp;
thisPrevious = thisTemp;
otherTemp = otherTemp->next;
}
}
*/
}
//--------------------------------------------------------------------
template <typename DataType>
StackLinked<DataType>& StackLinked<DataType>::operator=(const StackLinked& other)
// Overloaded assignment operator for the StackLinked class.
// Because this function returns a StackLinked object reference,
// it allows chained assignment (e.g., stack1 = stack2 = stack3).
{
// Self-assignment protection
if( this != &other ) return *this;
clear(); // Clear existing nodes
if( ! other.isEmpty() )
{
// Copy first node
top = new StackNode(other.top->dataItem, 0);
StackNode *otherTemp = other.top->next;
StackNode *thisTemp=0, *thisPrevious=top;
// Copy rest of nodes
while( otherTemp != 0 )
{
thisTemp = new StackNode(otherTemp->dataItem, 0);
thisPrevious->next = thisTemp;
thisPrevious = thisTemp;
otherTemp = otherTemp->next;
}
}
return *this;
}
//--------------------------------------------------------------------
template <typename DataType>
StackLinked<DataType>::~StackLinked()
// Destructor. Frees the memory used by a stack.
{
clear();
}
//--------------------------------------------------------------------
template <typename DataType>
void StackLinked<DataType>::push(const DataType& newDataItem) throw (logic_error)
// Inserts newDataItem onto the top of a stack.
{
if (isFull()) {
// Not likely with linked implementation
throw logic_error("push() while stack full");
}
top = new StackNode(newDataItem, top);
}
//--------------------------------------------------------------------
template <typename DataType>
DataType StackLinked<DataType>::pop() throw (logic_error)
// Removes the topmost item from a stack and returns it.
{
if (isEmpty()) {
throw logic_error("pop() while stack empty");
}
StackNode* temp = top;
top = top->next;
DataType value = temp->dataItem;
delete temp;
return value;
}
//--------------------------------------------------------------------
template <typename DataType>
void StackLinked<DataType>::clear()
// Removes all the data items from a stack.
{
for (StackNode* temp = top; top != 0; temp = top)
{
top = top->next;
delete temp;
}
// Invariant: At this point in the code, top == 0.
// Top does not heed to explicitly set to 0. It was
// either 0 before the loop, or emerged from the loop as 0.
}
//--------------------------------------------------------------------
template <typename DataType>
bool StackLinked<DataType>::isEmpty() const
// Returns true if a stack is empty. Otherwise, returns false.
{
return top == 0;
}
//--------------------------------------------------------------------
template <typename DataType>
bool StackLinked<DataType>::isFull() const
// Returns true if a stack is full. Otherwise, returns false.
{
return false;
/*
// Alternatively, can use implementation below.
// This is a somewhat awkward way to test if the list is full.
// If a node can be successfully allocated than the list is not
// full. If the allocation fails it is implied that there is no
// more free memory therefore the list is full.
// We are not aware of any other standard/portable way of
// performing the test. And this can fail due to external issues
// such as the system exhausting swap or another thread stealing
// the remaining memory between when isFull returns its result and
// the caller does something that assumes that isFull() returned
// a valid answer.
//
// Alternatives include just the line "return false", which is
// probably good enough in this context, or platform-dependent
// checks for available memory.
StackNode* temp;
DataType junk;
try
{
temp = new StackNode( junk, 0 );
}
catch ( bad_alloc &e )
{
return true;
}
delete temp;
return false;
*/
}
//--------------------------------------------------------------------
template <typename DataType>
void StackLinked<DataType>::showStructure() const
// Linked list implementation. Outputs the data elements in a stack.
// If the stack is empty, outputs "Empty stack". This operation is
// intended for testing and debugging purposes only.
{
if( isEmpty() )
{
cout << "Empty stack" << endl;
}
else
{
cout << "Top\t";
for (StackNode* temp = top; temp != 0; temp = temp->next) {
if( temp == top )
{
cout << '[' << temp->dataItem << "]\t";
}
else
{
cout << temp->dataItem << "\t";
}
}
cout << "Bottom" << endl;
}
}
#endif //#ifndef STACKLINKED_CPP
Here's the header file, StackLinked.h
//--------------------------------------------------------------------
//
// Laboratory 6 StackArray.h
//
// Class declaration for the array implementation of the Stack ADT
//
//--------------------------------------------------------------------
#ifndef STACKARRAY_H
#define STACKARRAY_H
#include <stdexcept>
#include <iostream>
using namespace std;
#include "Stack.h"
template <typename DataType>
class StackLinked : public Stack<DataType> {
public:
StackLinked(int maxNumber = Stack<DataType>::MAX_STACK_SIZE);
StackLinked(const StackLinked& other);
StackLinked& operator=(const StackLinked& other);
~StackLinked();
void push(const DataType& newDataItem) throw (logic_error);
DataType pop() throw (logic_error);
void clear();
bool isEmpty() const;
bool isFull() const;
void showStructure() const;
private:
class StackNode {
public:
StackNode(const DataType& nodeData, StackNode* nextPtr);
DataType dataItem;
StackNode* next;
};
StackNode* top;
};
#endif //#ifndef STACKARRAY_H
Here's another header file, Stack.h
//--------------------------------------------------------------------
//
// Laboratory 6 Stack.h
//
// Class declaration of the abstract class interface to be used as
// the basis for implementations of the Stack ADT.
//
//--------------------------------------------------------------------
#ifndef STACK_H
#define STACK_H
#include <stdexcept>
#include <iostream>
using namespace std;
template <typename DataType>
class Stack {
public:
static const int MAX_STACK_SIZE = 8;
virtual ~Stack();
virtual void push(const DataType& newDataItem) throw (logic_error) = 0;
virtual DataType pop() throw (logic_error) = 0;
virtual void clear() = 0;
virtual bool isEmpty() const = 0;
virtual bool isFull() const = 0;
virtual void showStructure() const = 0;
};
template <typename DataType>
Stack<DataType>::~Stack()
// Not worth having a separate class implementation file for the destuctor
{}
#endif // #ifndef STACK_H
So, I've included all corresponding headers since this program utilizes inheritance. Please continue to help me debug this program. All help is well-appreciated.
You probably want to replace
StackLinked<DataType>::StackNode(...)
by
StackLinked<DataType>::StackNode::StackNode(...)
that is the constructor of class StackNode called as usual StackNode::StackNode inside the class StackLinked<DataType>.

CXX0030 Expression cannot be evaluated

I have a misunderstanding here. I'm designing a Queue class which uses the Client class as the base unit. The list structure consists of a pointer to the next data and a variable for holding the Client object.
The Queue class has 2 ways of operating. The way of it's operating is determined by the bool MODE variable. If mode equals 1, then the Queue class uses placement new operator, and if not, it uses the new operator.
This is the Queue class's prototype:
class Queue
{
private:
const int max_lists;
int no_lists, counter;
char client_value;
list *chunk;
list *top;
const bool MODE;
void addFirst(const Client &c);
void addLast(const Client &c);
void deleteLast();
void deleteFirst();
void clean_mem();
void clean_mem(list *&pos);
list* malloc();//T* type
public:
Queue();
Queue(list *buffer,int no);
Queue(const Queue &q);
Queue& operator=(const Queue &q);
~Queue() { clean_mem(); }
void enqueue(const Client &c);
void timeoutCustomers();
void decreaseTimeout();
Client getCustomer() const;
void finishCustomer();
void show() const;
};
The functions definitions which contribute to the error given are here:
void Queue::addFirst(const Client &c)
{
if(top==nullptr)
{
top = malloc();
top->info = c;
top->next = nullptr;
}
else
{
list *add = malloc();
add->info = c;
add->next = top;
top = add;
}
}
list* Queue::malloc()
{
if(MODE)
{
if(no_lists==max_lists)
{
return nullptr;
}
else
{
list *tmp = chunk;
counter = 0;
while(counter++<max_lists)
{
client_value = (char)tmp->info;
if(client_value==-1 && tmp->next==nullptr)
{
return new(tmp) list;
}
tmp++;
}
return nullptr;
}
}
else
{
return new list;
}
}
And here's the list structure:
struct list { Client info; list *next; };
When I make an instance of the Queue class, I can choose whether I go on placement new or just the new operator.
If I choose the placement new, I'm have to send the address of an array of type list. The address is saved into chunk pointer. The top pointer holds the first address of the linked list.
Then, if I call the addFirst() function it stops at top->info = c. The error points to top->info :
CXX0030: Error: Expression cannot be evaluated.
But when I switch back to new operator, everything works. This tells me that there's a problem with the allocation of a new portion in the already allocated memory.
Can somebody give me a direction of what's the problem here?
Did you intend your malloc function like that? You have an 'else' block AFTER your functions definition and not all control paths return a value. I have a rewrite here that seems to match more with what I think you actually intend:
list* Queue::malloc()
{
if(MODE)
{
if(no_lists==max_lists)
{
return nullptr;
}
else
{
list *tmp = chunk;
counter = 0;
while(counter++<max_lists)
{
client_value = (char)tmp->info;
if(client_value==-1 && tmp->next==nullptr)
{
return new(tmp) list;
}
tmp++;
}
return nullptr;
}
}
else
{
return new list;
}
}

How do we include a struct in a c++ implementation file?

So I am trying to create my own implementation file which contains instructions for a Queue. I decided to use a linked list to implement the Queue class, meaning that I need to use my own Node struct. Unfortunately, I am stuck and don't know how to properly include this within the file.
This is what I have so far:
#include <string>
#ifndef NODE
template <class DataType>
struct Node
{
DataType data;
Node *next;
};
#endif
template <class DataType>
class Queue
{
public:
Queue();
bool isEmpty() const;
void push(const DataType& parameter);
bool peek(DataType& parameter) const;
bool pop(DataType& parameter);
void makeEmpty();
private:
Node<DataType>* front;
Node<DataType>* end;
};
template <class DataType>
Queue<DataType>::Queue()
: front(0), end(0)
{
}
template <class DataType>
bool Queue<DataType>::isEmpty() const {return 0 == front;}
template <class DataType>
void Queue<DataType>::push(const DataType& parameter)
{
Node<DataType>* node = new Node<DataType>;
node->data = parameter;
node->next = 0;
if (end) end->next = node;
else front = node;
end = node;
}
template <class DataType>
bool Queue<DataType>::peek(DataType& parameter) const
{
if (0 == front) return false; // failed
parameter = front->data;
return true; // success
}
template <class DataType>
bool Queue<DataType>::pop(DataType& parameter)
{
if (0 == front) return false; // failed
parameter = front->data;
Node<DataType>* p = front->next;
delete front;
front = p;
if (front == 0) end = 0;
return true; // success
}
template <class DataType>
void Queue<DataType>::makeEmpty()
{
end = 0;
Node<DataType>* p;
while (front)
{
p = front->next;
delete front;
front = p;
}
}
I'm not sure if I am enclosing the struct by the #ifndef correctly (i'm not even sure if this is the route I should be taking :/), should I be doing something similar to this or should I be doing something else with the code for the struct?
You can just drop the #ifdef/#endif entirely
This is a class template and it may occur many times in several tranlation units, as long as all the occurrences are identical (One Definition Rule)
Alternative
Since Node<> is purely a private concern, I'd make it a nested struct.
Here's a little demo making this more 'modern C++' style.
Edit Thanks to #R.MartinhoFernandes for showing a few more improvements and for reviewing this.
#include <memory>
template <typename T>
struct Queue {
Queue() : front(), end(/*nullptr*/) {}
// Copy-And-Swap idiom
// see http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Copy-and-swap
// or http://stackoverflow.com/questions/3279543/what-is-the-copy-and-swap-idiom
void swap(Queue& q) noexcept {
using std::swap;
swap(q.front, front);
swap(q.end, end);
}
Queue(Queue const& q) : front(), end() {
for(auto it=q.front.get(); it; it=it->next.get())
push(it->data);
}
Queue& operator=(Queue q) {
std::swap(*this, q);
return *this;
}
// end Copy-and-swap
// prevent stack overflows in ~Node if the list grows large (say >1k elements)
~Queue() { clear(); }
bool isEmpty() const {
return !front;
}
void push(T const& data) {
Ptr node(new Node(data));
if (end)
end->next = std::move(node);
else
front = std::move(node);
end = node.get();
}
bool peek(T& data) const {
if(front) data = front->data;
return front.get();
}
bool pop(T& data) {
if(!front) return false;
data = front->data;
front = std::move(front->next);
if(!front) end = nullptr;
return true;
}
void clear() {
end = nullptr;
while(front) front = std::move(front->next);
}
private:
struct Node;
typedef std::unique_ptr<struct Node> Ptr;
struct Node {
Node(T data) : data(std::move(data)), next() {}
T data;
Ptr next;
};
Ptr front;
Node* end;
};
#include <iostream>
int main(int argc, const char *argv[]) {
Queue<int> test;
test.push(1);
test.push(2);
test.push(3);
test.push(5);
test.clear();
test.push(32028);
test.push(10842);
test.push(1839);
test.push(23493);
test.push(9857);
int x;
test.peek(x);
while(test.pop(x)) {
std::cout << x << '\n';
}
}
Note: Perhaps the code in push has been golfed a bit too far, but hey, it shows you how modern C++ requires much less handholding (even without std::make_unique).
Note how I think Clang correctly handles the following version (i.e. with implicit std::move):
void push(const DataType& parameter) {
end = ((end? end->next : front) = Ptr(new Node(parameter))).get();
}
I'm not quite sure why gcc rejects it.