I'm learning C++, and we were given an exercise to make a stack class using a class template and pointers. I'm not yet fully understanding the implementation of a stack or pointers so I gave it a go and made this class:
template <class T>
class Stack_Class {
public:
T* stack;
int item_quantity;
T* First_item;
int Max_quantity;
Stack_Class(int value);
~Stack_Class();
bool Add(T value);
T Pop();
int GetMax_Quantity();
bool Full();
bool Empty();
};
template <class T>
Stack_Class<T>::Stack_Class(int value) {
if (value > 0) {
stack = new T[value];
First_item = stack;
item_quantity = 0;
Max_quantity = value;
}
}
template <class T>
Stack_Class<T>::~Stack_Class() {
if (First_item) {
delete First_item;
}
}
template<class T>
bool Stack_Class<T>::Add(T num) {
if (item_quantity <Max_quantity) {
*stack = num;
stack++;
item_quantity++;
return true;
}
else return false;
}
template<class T>
T Stack_Class<T>::Pop() {
if (!Empty()) {
item_quantity--;
return stack[item_quantity];
}
return NULL;
}
template<class T>
bool Stack_Class<T>::Empty() {
return (item_quantity == 0);
}
template <class T>
int Stack_Class<T>::GetMax_Quantity() {
return Max_quantity;
}
And the main class would be:
#include <iostream>
#include "Stack_Class.h"
void main() {
Stack_Class<int> intStack(3);
intStack.Add(1);
intStack.Add(2);
intStack.Add(3);
int count = intStack.GetMax_Quantity();
for (int i = 0; i < count; i++) {
std::cout << "Pop No: " << i << " - Elemento: " << intStack.Pop() << std::endl;
}
}
Though as a result I'm getting all random numbers instead of the ones I gave it in intStack. Add, so my question would be I'm implementing the pointer correctly here?
You need to deincrement the stack pointer before you reference it within Pop():
template<class T>
T Stack_Class<T>::Pop(){
if (!Empty()){
item_quantity--;
stack--;
return *stack;
}
return NULL;
}
Your array access stack[item_quantity] does not work because you increment stack in Add. So after construction, the memory pointed to by stack looks like this
0xff65f96f <-- *(stack + 0)
0x0eec604f <-- *(stack + 1)
0x05be0582 <-- *(stack + 2)
0x29b9186e <-- *(stack + 3)
The hexdecimal values represent random garbage coincidentely located in the memory at the time of allocation. This is because memory allocated by new is not initialized to something nice. After adding three values, it looks like this
1 <-- *(stack - 3)
2 <-- *(stack - 2)
3 <-- *(stack - 1)
0x29b9186e <-- *(stack + 0)
0xf66eff06 <-- *(stack + 1)
0x357eb508 <-- *(stack + 2)
In the first call of Pop, you access stack[2] = *(stack + 2), because item_quantity is 2 after deincrementing it. The two consecutive calls to Pop access stack[1] and stack[0]. As you can see above, you never actually reference the values you’ve put into the stack.
You are mixing up the pointer incrementing semantic in the Add method and the indexing semantic in the Pop method.
Since you need the index for the Empty method and so on, I would fix your Add method instead of the Pop as can be seen below.
Otherwise, you would end up still using the indexing in some method(s), but not in other. It would not look consistent to me.
template<class T>
bool Stack_Class<T>::Add(T num){
if (item_quantity <Max_quantity){
stack[item_quantity++] = num;
return true;
}
else return false;
}
Yet another problem in your code is this:
stack = new T[value];
but you seem to only delete the first element in the pointer. That is a guaranteed (and potentially not negligible) memory leak.
Even if you fix all that, your code would not still compile since you are trying to return void, whereas a C++ program should return int, so change this:
void main(){
...
}
to:
int main(){
...
}
... and return an integer like 0 correspondingly.
You would also need to fix this warning:
Stack_Class.h:56:13: warning: converting to non-pointer type ‘int’ from NULL [-Wconversion-null]
return NULL;
^
By for instance change NULL to 0.
Having fixed all that, the output is like this:
Pop No: 0 - Elemento: 3
Pop No: 1 - Elemento: 2
Pop No: 2 - Elemento: 1
You can also see the code running on ideone.
For your convenience, this is the whole working code after those fixes:
template <class T>
class Stack_Class{
public:
T* stack;
int item_quantity;
T* First_item;
int Max_quantity;
Stack_Class(int value);
~Stack_Class();
bool Add(T value);
T Pop();
int GetMax_Quantity();
bool Full();
bool Empty();
};
template <class T>
Stack_Class<T>::Stack_Class(int value){
if (value > 0){
stack = new T[value];
First_item = stack;
item_quantity = 0;
Max_quantity = value;
}
}
template <class T>
Stack_Class<T>::~Stack_Class(){
if (First_item){
delete First_item;
}
}
template<class T>
bool Stack_Class<T>::Add(T num){
if (item_quantity <Max_quantity){
*stack = num;
stack++;
item_quantity++;
return true;
}
else return false;
}
template<class T>
T Stack_Class<T>::Pop(){
if (!Empty()){
item_quantity--;
return stack[item_quantity];
}
return NULL;
}
template<class T>
bool Stack_Class<T>::Empty(){
return (item_quantity == 0);
}
template <class T>
int Stack_Class<T>::GetMax_Quantity(){
return Max_quantity;
}
Related
I was building a small template stack class for a side project and it appeared to be working correctly. However, when I tried it with strings it doesn't appear to work. I have no compilation errors or warnings. I simply get no output. I'm a little rusty in C++ but I wasn't expecting to get blocked by a problem that seems this simple.
My main function (for testing):
#include <iostream>
#include <fstream>
#include <string>
#include "myStack.h"
int main()
{
bool repeat = true;
int option = -1;
std::cout << "Option (1 - String | 2 - Integer) : ";
std::cin >> option;
std::cout << "\n";
switch (option)
{
case 1:
{
myStack<std::string> stringStack;
stringStack.push("!");
stringStack.push("there");
stringStack.push("Hello");
stringStack.show();
break;
}
case 2:
{
myStack<int> intStack;
intStack.push(3);
intStack.push(2);
intStack.push(1);
intStack.show();
break;
}
default:
break;
}
std::cout << "\n";
return 0;
}
Relevant parts of my stack class:
#pragma once
template <typename T>
class myStack
{
private:
T *elements;
size_t capacity;
public:
myStack();
T top();
size_t size();
void push(T pushed);
void pop();
bool isEmpty();
void show(std::ostream &out = std::cout);
};
template <typename T>
myStack<T>::myStack()
{
this->elements = NULL;
this->capacity = 0;
}
template <typename T>
void myStack<T>::push(T pushed)
{
this->elements = (T *)realloc(this->elements, (this->capacity + 1) * sizeof(T));
this->elements[this->capacity] = pushed;
this->capacity++;
}
template<typename T>
void myStack<T>::show(std::ostream &out)
{
for (int i = this->capacity - 1; i >= 0; i--)
{
out << this->elements[i] << std::endl;
}
}
Use of
this->elements = (T *)realloc(this->elements, (this->capacity + 1) * sizeof(T));
this->elements[this->capacity] = pushed;
to manage an array of std::strings is not right. Use of realloc to allocate memory is ok. However, it does not initialize the object properly. The second line is cause for undefined behavior since the object was not initialized properly.
If you are allowed to use std::vector, use it.
template <typename T>
class myStack
{
private:
std::vector<T> elements;
...
};
Then, use of capacity can be replaced by elements.size().
push can be simplified to:
template <typename T>
void myStack<T>::push(T pushed)
{
this->elements.push_back(pushed);
}
You'll have to update show() accordingly too.
Good evening guys, I'm totally new to C++ and I've been having some troubles with it.
Now, I'm trying to make a List, after a lot of undos and corrections, I found this error that I cannot solve.
#define MAXLIST 100
template <typename T>
class List {
private:
int maxList;
int last = 0;
T* List;
public:
List();
explicit List(int tam);
bool listIsFull();
void destroyList();
List<T>() {
last = -1;
maxList = MAXLIST;
list = new T[maxList];
}
List<T>(int tam) {
last = -1;
maxList = tam;
list = new T[maxList];
}
void destroyList() {
last = -1;
}
bool listIsFull() {
if(last == MAXLIST -1)
return true;
else
return false;
}
}
Both methods destroyList() and listIsFull(), in my IDE show an error like: 'Cannot be overloaded'
And both constructors show an error like: 'Does not name a type'
What is that, that i'm doing wrong?
Thank you in advance.
The way your code appeared to me, you tried to prototype your class and then provide implementation below it, I simply added correct scope and template operators.
#define MAXLIST 100
template <typename T>
class List {
private:
int maxList;
int last = 0;
T* List;
public:
List();
explicit List(int tam);
bool listIsFull();
void destroyList();
};
template<typename T>
List<T>::List<T>() {
last = -1;
maxList = MAXLIST;
list = new T[maxList];
}
template<typename T>
List<T>::List<T>(int tam) {
last = -1;
maxList = tam;
list = new T[maxList];
}
template<typename T>
void List<T>::destroyList() {
last = -1;
}
template<typename T>
bool List<T>::listIsFull() {
if (last == MAXLIST - 1)
return true;
else
return false;
}
I'm looking for an efficient way to check if a POD variable is altered between two cycles. I've come up with this solution:
class Foo {
public:
template<typename T>
bool isChanged(T& entry);
void endCycle();
private:
std::map<void*,size_t> entryMap; // <Address orig.,Size>
std::map<void*,void*>oldVals; // <Address orig., Address cpy.>
};
template<typename T> bool Foo::isChanged(T& entry)
{
entryMap[&entry] = sizeof(T);
if(oldVals[&entry] == NULL)
return false;
if(memcmp(&entry, oldVals[&entry], entryMap[&entry]))
return true;
else
return false;
}
void Foo::endCycle()
{
// Copy all the bytes to save them for the next cycle
for( std::map<void*,size_t>::iterator entryIt = entryMap.begin();
entryIt != entryMap.end();
++entryIt)
{
if(oldVals[entryIt->first] == NULL)
oldVals[entryIt->first] = malloc(entryIt->second);
memcpy(oldVals[entryIt->first], entryIt->first, entryIt->second);
}
}
Now i can use it like this:
Foo gBar;
void aFunction()
{
int ar;
char ba[3][3];
// Some code where ar and ba are filled
if(gBar.isChanged(ar))
// Do Something
if(gBar.isChanged(ba))
// Do Something
gBar.endCycle();
}
Is this an efficient way? My goal was a method which is very easy to use inside various cyclically called functions. I cleaned all the init and free logic from the code. Any suggestions? I especially don't like the oldshool malloc, memcpy and memcmp stuff but i don't know any other way how to do it.
Edit: Found a good solution based on Red Alerts suggestions.
I think you can use templates a little more effectively here.
template <typename T>
class Foo
{
public:
static std::map<T*, T> values;
static bool isChanged(T& entry)
{
auto it = values.find(&entry);
if(it == values.end())
{
values[&entry] = entry;
}
else if(entry != it->second)
{
it->second = entry;
return true;
}
return false;
}
};
template <typename T>
std::map<T*, T> Foo<T>::values;
int main() {
int ar = 3;
cout << Foo<int>::isChanged(ar) << endl; // 0
ar = 4;
cout << Foo<int>::isChanged(ar) << endl; // 1
for(auto& value : Foo<int>::values)
cout << value.second << endl; // 4
return 0;
}
This way you get one map per type, and you don't have to worry about inadvertently messing up an alias. You do need to define operator != and have a working copy constructor for your types, but that is much better than blindly using memcmp and memcpy.
You can also make further template specializations for arrays if you need to compare those (will be a bit more code, but nothing very complicated)
Edit: To get you started, this is what your template signature should look like:
template<class T, size_t N> bool isChanged(T(&entry)[N]); //will be called for stack allocated arrays
Or you can use char* to alias all of your values. This will let you use a single map for everything (like you were doing before, but this has no memcpy/memcmp). It will only work for POD. We could manually call the destructor when overwriting the buffer, but since there is no good way to do this in the class's destructor, it's probably best to leave out heap allocated data altogether.
class Foo
{
std::map<char**, char*> values;
public:
~Foo()
{
for(auto& value : values)
{
delete[] value.second;
}
}
template<typename T> bool isChanged(T& entry)
{
char** addr = reinterpret_cast<char**>(&entry);
auto it = values.find(addr);
if(it == values.end())
{
alignas(T) char* oldBuf = new char[sizeof(T)];
T* oldEntry = new(oldBuf) T;
*oldEntry = entry;
values[addr] = oldBuf;
}
else if(entry != *(reinterpret_cast<T*>(it->second)))
{
T* oldEntry = new(it->second) T;
*oldEntry = entry;
return true;
}
return false;
}
};
After many hours i think i found a good solution. The call stays easy and there are no casts. It's a lot more complex than the C-Style version with memcopy but I think its nicer and has also the benefit that it works with complex data not just POD.
class Manager
{
public:
~Manager()
{
funcPtrs.clear();
}
void adFnc(void(*function)())
{
funcPtrs.push_back(function);
}
void runAll()
{
for(auto& val : funcPtrs)
val();
}
private:
std::vector<void (*)()> funcPtrs;
};
Manager gAllClearManager;
template<typename T>
class Data
{
public:
Data()
{
gAllClearManager.adFnc(clearValues);
}
static void clearValues()
{
values.clear();
}
static std::map<T*,std::vector<T>>& getValues() { return values; }
private:
static std::map<T*,std::vector<T>> values;
};
template <typename T>
static bool isChanged(T& entry)
{
const static Data<T>* dataP = new Data<T>();
static std::map<T*,std::vector<T>>& values = dataP->getValues();
auto it = values.find(&entry);
if(it == values.end())
{
values[&entry].push_back(entry);
}
else if(entry != it->second[0])
{
it->second[0] = entry;
return true;
}
return false;
}
template<typename T, size_t N>
bool isChanged(T (&entry)[N])
{
const static Data<T>* dataP = new Data<T>();
static std::map<T*,std::vector<T>>& values = dataP->getValues();
auto it = values.find(entry);
if( it == values.end())
{
for(int i = 0; i < N ; ++i )
values[entry].push_back(entry[i]);
return false;
}
else
{
for(int i = 0; i < N ; ++i )
{
if(it->second[i] != entry[i])
{
for(int j = 0; j < N ; ++j )
{
it->second[j] = entry[j];
}
return true;
}
}
}
return false;
}
template<typename T>
std::map<T*, std::vector<T>> Data<T>::values;
Now i can use it like:
int main() {
int ar;
std::string ba[6];
if(isChange(ar))
// Do something
if(isChange(ba))
// Do something
}
My first template is finally working! :) Thanks again Red Alert.
There are many questions like this but after looking at some cases, I guess this question is case-specific so I post my code and pointed out where the problem takes place may you be patient reading my code?
uniBTree.h
#ifndef uniBTree_H
#define uniBTree_H
#include "uniTreeNode.h"
#include <cassert>
template<class T>
class uniBTree {
private:
uniTreeNode<T> *root;
int delete_helper(uniTreeNode<T> *);
uniTreeNode<T> *insert_helper(uniTreeNode<T> *, const T);
void in_print_helper(const uniTreeNode<T> *) const;
void pre_print_helper(const uniTreeNode<T> *) const;
void post_print_helper(const uniTreeNode<T> *) const;
public:
uniBTree(void);
uniBTree(uniTreeNode<T> *r);
~uniBTree(void);
void insert(const T i);
void in_print(void) const;
void pre_print(void) const;
void post_print(void) const;
};
template<class T>
uniBTree<T>::uniBTree(void)
{
root = NULL;
}
template<class T>
uniBTree<T>::uniBTree(uniTreeNode<T> *r)
{
root = r;
}
template<class T>
int uniBTree<T>::delete_helper(uniTreeNode<T> *n)
{
int count = 0;
if (n == NULL)
return 0;
count += delete_helper(n->get_left());
count += delete_helper(n->get_right());
delete n;
count++;
return count;
}
template<class T>
uniBTree<T>::~uniBTree(void)
{
int count = delete_helper(root);
std::cout << "uniBTree<T>::~uniBTree<T>(void)\n";
std::cout << count << " nodes deleted\n";
}
template<class T>
void uniBTree<T>::in_print() const
{
in_print_helper(root);
}
template<class T>
void uniBTree<T>::pre_print() const
{
pre_print_helper(root);
}
template<class T>
void uniBTree<T>::post_print() const
{
post_print_helper(root);
}
template<class T>
void uniBTree<T>::in_print_helper(const uniTreeNode<T> *current) const
{
if (current == NULL)
return;
in_print_helper(current->get_left());
current->print();
in_print_helper(current->get_right());
}
template<class T>
void uniBTree<T>::pre_print_helper(const uniTreeNode<T> *current) const
{
if (current == NULL)
return;
current->print();
pre_print_helper(current->get_left());
pre_print_helper(current->get_right());
}
template<class T>
void uniBTree<T>::post_print_helper(const uniTreeNode<T> *current) const
{
if (current == NULL)
return;
post_print_helper(current->get_left());
post_print_helper(current->get_right());
current->print();
}
template<class T>
void uniBTree<T>::insert(const T i)
{
if (root == NULL)
root = new uniTreeNode<T>(i, NULL, NULL);
else
insert_helper(root, i);
}
template<class T>
uniTreeNode<T> *uniBTree<T>::insert_helper(uniTreeNode<T> *current, const T i)
{
if (current == NULL) {//this is will only dealed by attempting to visit leaves...
//if root is null, it'll be handled in insert
uniTreeNode<T> *child = new uniTreeNode<T>(i, NULL, NULL);
assert(child != NULL);
return(child);
}
if (i < current->get_data())
current->set_left(insert_helper(current->get_left(), i));
else
current->set_right(insert_helper(current->get_right(), i));
return(current);
}
#endif
uniTreeNode.h
#ifndef uniTreeNode_H//for redefinition
#define uniTreeNode_H
#include <iostream>
//using namespace std; don't use using namespace xxx and include source file in .h file
template<typename T>
class uniTreeNode {
private:
T data;
uniTreeNode<T> *left;
uniTreeNode<T> *right;
public:
//uniTreeNode<T>(void);
uniTreeNode(T d, uniTreeNode<T> *l, uniTreeNode<T> *r);
T get_data(void) const;
uniTreeNode<T> *get_left(void) const;
uniTreeNode<T> *get_right(void) const;
void set_left(uniTreeNode<T> *l);
void set_right(uniTreeNode<T> *r);
void print() const;
};
template<typename T>
uniTreeNode<T>::uniTreeNode/*remember syntax here*/
(T d , uniTreeNode<T> *l = NULL, uniTreeNode<T> *r = NULL)
{
data = d;
left = l;
right = r;
}
template<typename T>
T uniTreeNode<T>::get_data(void) const
{
return data;
}
template<typename T>
uniTreeNode<T> * uniTreeNode<T>::get_left(void) const
{
return left;
}
template<typename T>
uniTreeNode<T> * uniTreeNode<T>::get_right(void) const
{
return right;
}
template<typename T>
void uniTreeNode<T>::set_left(uniTreeNode<T> *l)
{
left = l;
}
template<typename T>
void uniTreeNode<T>::set_right(uniTreeNode<T> *r)
{
right = r;
}
template<typename T>
void uniTreeNode<T>::print() const
{
std::cout << "data is " << data << std::endl;
}
#endif
date.h
#include <ostream>
class date{
private:
int y;
int m;
int d;
public:
date();//default constructor
date(const long int);//used by cplr as convert constructor
date(int, int , int);
friend bool operator<(const date &d1, const date &d2);//d1 is for left-hand date
friend bool operator>(const date &d1, const date &d2);
bool operator==(date d);
bool operator!=(date d);
date &operator=(date d);
friend std::ostream &operator<<(std::ostream &out, date d);
friend std::istream &operator>>(std::istream &in, date d);
};
date.cc
#include <iostream>
#include <cstdio>
#include <time.h>
#include <cstring>
#include "date.h"
date::date(){
y = m = d = 0;
}
date::date(int Y, int M, int D){
y = Y;
m = M;
d = D;
}
date::date(const long int s){//#second since 1970/1/1 00:00:00
struct tm *buf;
buf = gmtime(&s);
y = (buf->tm_year+1900);
m = buf->tm_mon+1;
d = buf->tm_mday;
}
bool operator<(const date &d1, const date &d2){
bool result;//sizeof(bool) is 1
if(d1.y < d2.y) result = true;
else if(d1.y == d2.y){
if(d1.m < d2.m) result = true;
else if(d1.m == d2.m){
if(d1.d < d2.d) result = true;
else result = false;
}
else result = false;
}
else result = false;
return result;
}
bool operator>(const date &d1, const date &d2){
bool result;//sizeof(bool) is 1
if(d1.y > d2.y) result = true;
else if(d1.y == d2.y){
if(d1.m > d2.m) result = true;
else if(d1.m == d2.m){
if(d1.d > d2.d) result = true;
else result = false;
}
else result = false;
}
else result = false;
return result;
}
bool date::operator==(date d){
return (this->y==d.y && this->m==d.m && this->d==d.d);
}
bool date::operator!=(date d){
return (this->y!=d.y || this->m!=d.m || this->d!=d.d);
}
date &date::operator=(date d){
this->y = d.y;
this->m = d.m;
this->d = d.d;
return *this;
}
std::ostream &operator<<(std::ostream &out, date d){
out << d.y << "/" << d.m << "/" << d.d << std::endl;
return out;
}
std::istream &operator>>(std::istream &in, date d){
in >> d.y >> d.m >> d.d ;
return in;
}
main function
#include "uniBTree.h"
#include "date.h"
#include <cstdio>
int main(){
date d1 = 100000000;//convert constructor
uniTreeNode<date> node(d1, NULL, NULL);
printf("%p %p\n", node.get_left(), node.get_right());
std::cout << node.get_data() << std::endl;
date d2 = 86401;
date d3 = 200000000;
uniBTree<date> btree(&node);
return 0;
}
I tested and found that its &node that is invalid. I think it is because it tries to "release" btree at the end of the program and when the root is encountered, because it points to node, it can't perform good thing.
I have two question:
if construct a node like what I did,(uniTreeNode<date> node(xxx, xxx, xxx);) was the object "NEW"ed by the program?
for the uniTreeNode<T> class template, I didn't write its destructor!! So, like what I say above, when node,which is pointed by root of btree, is to be released is there so-called "default destructor"? and is it called here ? And most importantly, is "DELETE" used by the program?
If one of the two question above is no, is it why the problem arise?
EDIT: now the problem is shown, but how can I adjust my code to fix this? any one any idea?
EDIT: just modify like this:
uniTreeNode<date> *nodeptr = new uniTreeNode<date>(d1, NULL, NULL);
p.s. if not indirectly using a pointer to refer to our root of the btree(thus using new), new isn't used, and delete shouldn't be used; by this choice, delete_helper of uniTreenode should use this:
if(n != root){
delete n;
count++;
}
but this does not solve the problem...
the ultimate question is:
"can we release object without using delete(because it isn't obtained from newing) in c++?"
REPLY:
My "release"/"allocated" is actually saying about the memory, without specifying HOW it is done...but it's a big issue anyway
You say "you can do that but it is almost always the wrong answer";you mean that I should use DELETE but not directly call the destructor?(actually that doesn't seem proper at all)
-->please justify here
Btw, for those instance NEWed by me, is it necessary for them to be DELETED by a statement if I want to release them? or they'll also be dealt like those automatic variable instance?(back when out of scope, by compiler)
-->please correct the above if needed
another Q: isn't there ANY existing statement I can use to do things, like what DELETE does, for those automatic instance? or, I can only call destructor, if I wish?
Answer to your questions:
No, it allocated memory on the stack at compilation time and just ran the constructor on that.
You can't delete a pointer not allocated using new. The compiler inserts a call to the destructor (default or not) for uniTreeNode when the object node is done in main().
So to surmise, you cannot use delete on a pointer that is not allocated using new.
Simplest fix would be to allocate node using new:
uniTreeNode<date>* node = new uniTreeNode<date>(d1);
uniBTree<date> btree(node);
Learn to use valgrind.
It tells you right away what the problem is, you're deleting a stack object in the uniBTree destructor
==23648== Invalid free() / delete / delete[] / realloc()
==23648== at 0x4A0736C: operator delete(void*) (vg_replace_malloc.c:480)
==23648== by 0x400D78: uniBTree<date>::delete_helper(uniTreeNode<date>*) (uniBTree.h:48)
==23648== by 0x400CD5: uniBTree<date>::~uniBTree() (uniBTree.h:56)
==23648== by 0x400B91: main (main.cc:17)
==23648== Address 0x7fefffab0 is on thread 1's stack
==23648==
The destructor calls delete but &node was not created by new (you can tell that because you didn't write new!)
I have a code to remove the first element of a string array.But its deleting the last entered element.How do I delete the first element in the queue without using STL and how do I reset the queue to empty.Here is my class declaration as Queue.h file and QueueImpl.h as its a template file.You got to include all the functions implemented in Queueimpl.h file and then include it in main.I have successfully deleted the element from the queue and I can see that when printing queue but while searching it, the deleted element still exists why is it that
Queue.h
template <class Type>
class Queue
{
private:
int counter;
int Queue_size;
Type* Contents;
int Front, Back;
int items_in_queue = 0;
public:
Queue(int queue_size = 10);
~Queue();
bool Empty() const;
bool Full() const;
void Remove();
int Add(const Type& new_element);
int QueueSize();
Type front();
int search(string &element,int numElm);
void clear();
bool IsDigitsOnly(string &strn);
};
#endif
QueueImpl.h
#pragma once
#ifndef QUEUETEMPLATE_H
#define QUEUETEMPLATE_H
#include<string>
#include "queue.h"
const int MAX_SIZE = 10;
// Constructor
int counter = 0;
template<class Type>
Queue<Type>::Queue(int queue_size) :
Queue_size(queue_size),
Contents(new Type[queue_size + 1]),
Front(0), Back(0)
{}
// Destructor
template<class Type>
Queue<Type> :: ~Queue()
{
delete[] Contents;
}
// Tests
template<class Type>
void Queue<Type>::clear()
{
while (!Empty()) {
Front = Back = -1;
}
}
template<class Type>
bool Queue<Type>::Empty() const
{
return (Front == Back) ? true : false;
}
template<class Type>
bool Queue<Type>::Full() const
{
return ((1 + Back) % (Queue_size + 1) == Front) ? true : false;
}
/
}
#endif
Ok, now it is enough. I do not want to criticize your code style. It would be better if you would demonstrate an example of usage. Without it I assume Type is std::string. I remove <Type> for simplifications. Let start.
IsDigitsOnly does not relate to your class. It is better to move it into a separate function.
Why you need queue_size + 1 of elements in the array Contents if queue_size is desired?
The constructor Queue::Queue initializes an empty queue object, zeros Front and Back. It should be done in Queue::clear: Front = Back = 0 instead of Front = Back = -1.
Simply return Front == Back instead of return (Front == Back) ? true : false.
Queue::Full would be identical to Queue::Empty. They both should check counter.
Queue::Remove: the condition if (Front == Back) is always false, since the same condition is in if (Empty()). The final else is right, since you are using correct Queue_size. You must counter-- there.
In Queue::Add the erroneous Queue_size + 1 is used.
Queue::search does not use Front and Back therefore it is wrong. See below.
Let stop here. I hope you are able to move forward yourself.
New to the 5 and 8.
template<class Type>
bool Queue<Type>::Empty() const
{
return counter == 0;
}
template<class Type>
bool Queue<Type>::Full() const
{
return counter == Queue_size;
}
template<class Type>
int Queue<Type>::search(const Type& element, int numElm)
{
if (numElm < Front || numElm >= Back)
return -1;
// Used as a subscript to search array
for (int index = numElm; index != Back; index = (index + 1) % Queue_size)
{
if (Contents[index] == element) // If the value is found
return index;
}
return -1;
}