I wrote a queue class in C++ using arrays of fixed width. Could anyone review my code ? I would appreciate any comment and recommendations. It works like a circular queue, so I handled back and front pointers in that manner.
#include <stdlib.h>
#include <iostream>
template <class T>
class Queue {
public:
Queue(void);
Queue(Queue<T>& copyQueue);
bool empty(void) const;
std::size_t size(void) const;
void clear(void);
T front(void) const;
void pop(void);
void push(T& item);
void print(std::ostream& os);
private:
static const std::size_t MAX_SIZE = 50;
T list[MAX_SIZE];
T* frontPtr;
T* backPtr;
std::size_t sizeQ;
};
template <class T>
Queue<T>::Queue(void) {
frontPtr = nullptr;
backPtr = nullptr;
sizeQ = 0;
}
template <class T>
Queue<T>::Queue(Queue<T>& copyQueue) {
frontPtr = nullptr;
backPtr = nullptr;
sizeQ = 0;
if(copyQueue.backPtr >= copyQueue.frontPtr){
for(T* i = copyQueue.frontPtr; i <= copyQueue.backPtr; i++){
push(*i);
}
}
else {
for(T* i = copyQueue.frontPtr; i <= (copyQueue.list + MAX_SIZE -1); i++){
push(*i);
}
for(T* i = copyQueue.list; i <= copyQueue.backPtr; i++) {
push(*i);
}
}
}
template <class T>
bool Queue<T>::empty(void) const {
return (sizeQ == 0);
}
template <class T>
std::size_t Queue<T>::size(void) const {
return sizeQ;
}
template <class T>
void Queue<T>::clear(void) {
frontPtr = nullptr;
backPtr = nullptr;
sizeQ = 0;
}
template <class T>
T Queue<T>::front(void) const {
if(frontPtr == nullptr) {
std::cerr << "Queue is empty. No front value" << '\n';
}
else {
return *frontPtr;
}
}
template <class T>
void Queue<T>::pop(void) {
if(sizeQ == 0) {
std::cerr << "Queue is empty. Can't pop." << '\n';
}
else{
frontPtr = list + ((frontPtr - list + 1) % MAX_SIZE);
sizeQ -= 1;
}
}
template <class T>
void Queue<T>::push(T& item) {
if(sizeQ == MAX_SIZE) {
std::cerr << "Queue is full. Can't push" << '\n';
}
else{
if(sizeQ == 0) {
frontPtr = backPtr = list;
}
else {
backPtr = list + ((backPtr - list + 1) % MAX_SIZE);
}
*backPtr = item;
sizeQ += 1;
}
}
template <class T>
void Queue<T>::print(std::ostream& os) {
if(backPtr >=frontPtr){
for(T* i = frontPtr; i <= backPtr; i++){
os << *i << '\n';
}
}
else {
for(T* i = frontPtr; i <= (list + MAX_SIZE -1); i++){
os << *i << '\n';
}
for(T* i = list; i <= backPtr; i++) {
os << *i << '\n';
}
}
}
Edit: Not using googletest
, but a simple main function to test the Queue.h
can be found below:
#include "Queue.h"
int main() {
Queue<int> newQueue;
for(int i=1; i<110; i = i+2)
newQueue.push(i);
newQueue.pop();
newQueue.pop();
newQueue.pop();
newQueue.pop();
int i = 999;
newQueue.push(++i);
newQueue.push(++i);
newQueue.push(++i);
newQueue.push(++i);
newQueue.print(std::cout);
Queue<int> copiedQueue(newQueue);
std::cout << copiedQueue.size() << '\n';
copiedQueue.print(std::cout);
for(int i=1; i<11; i = i+2)
copiedQueue.pop();
newQueue.print(std::cout);
std::cout << copiedQueue.empty();
std::cout << newQueue.empty();
copiedQueue.print(std::cout);
return 0;
}
-
\$\begingroup\$ You've obviously put a lot of time into this, could you please add some code that uses this class or tests it? \$\endgroup\$pacmaninbw– pacmaninbw ♦2019年08月19日 22:02:53 +00:00Commented Aug 19, 2019 at 22:02
-
\$\begingroup\$ @pacmaninbw , I added a main function to test the code. \$\endgroup\$Erdem Tuna– Erdem Tuna2019年08月20日 07:09:28 +00:00Commented Aug 20, 2019 at 7:09
2 Answers 2
Some general improvements:
- Use
<cstdlib>
, not<stdlib.h>
. The latter is a deprecated header that is kept for C compatibility. It should not be used in new C++ code. - Do not use
void
in an empty parameter list. It is counterintuitive and is not necessary in C++ at all. It is only used in C prototypes. - The copy constructor should take by const reference because it does not modify the argument. Same for
push
. - You are using assignment in constructors when you ought to use member initializer clauses. This is bad practice.
front
should return by const reference, not by value. Returning by value makes an unnecessary copy.MAX_SIZE
is not a macro and should not be in ALL_CAPS. And it should beconstexpr
. Or better, a template parameter.- It is advised in C++ to use
std::array
instead of raw arrays.
There are still many things to improve, but this should be enough to get you started.
-
\$\begingroup\$ thank you for having time to analyze and elaborate the class. Regarding your
8
th suggestion, shall I remove thesizeQ
variable? Then, I should track the fullness of the queue bybackPtr - frontPtr
? This would create problem as it is a circular queue. Could you please inform me a bit more on this? \$\endgroup\$Erdem Tuna– Erdem Tuna2019年08月22日 20:55:01 +00:00Commented Aug 22, 2019 at 20:55 -
1\$\begingroup\$ @ErdemTuna Oops, I didn't realize that this is a circular queue. Sorry for that. Still, the
sizeQ
variable contains more information than it should and you have to keep it synchronized. You may replace it with abool
variable indicating whether the queue is empty, I guess. I'll delete that bullet. \$\endgroup\$L. F.– L. F.2019年08月22日 20:58:59 +00:00Commented Aug 22, 2019 at 20:58
1) swap from using an array to either vector or std::array, N> elems; current when using std::array the types that you may hold in you queue are limited to default constructable
2) copy constructor should be passed by const ref
3) Perhapse think about moving the max size parameter as a template perameter template class Queue
4) I noticed there is not a assignment operator is this on purpose?
5) correct me if I am wrong but when implementing a circular queue and a push runs out of space shouldn't you pop from the front and push to back
-
\$\begingroup\$ Thank you for the evaluation. Regarding
3
, why and how shouldMAX_SIZE
be a template class? Regarding4
, I just didn't implement it, I should write that part. Regarding5
, I wasn't aware of that fact, but I guess you are right. \$\endgroup\$Erdem Tuna– Erdem Tuna2019年08月31日 18:13:39 +00:00Commented Aug 31, 2019 at 18:13 -
1\$\begingroup\$ @ErdemTuna 3 - why? Because it would allow for a more flexible use case of the class now the max size can still be determined at compile time but different instances can have different max sizes if you wish. How?
c++ template <class T, std::size_t MAX_SIZE = 50> class Queue {
\$\endgroup\$swaggg_pickle– swaggg_pickle2019年09月01日 22:31:22 +00:00Commented Sep 1, 2019 at 22:31