Implementing a queue: questions and clarificationThread-safe queueSTL queue implementationArray-like container for uints shorter than 8 bits (Rev 1)Queue with std::vectorAsynchronously load and unload a queueLockless SCSP queueUpdatable priority queueFixed Size QueueImplementation of a queueimplementing a queue using std::vector
Is "remove commented out code" correct English?
Is it unprofessional to ask if a job posting on GlassDoor is real?
Infinite Abelian subgroup of infinite non Abelian group example
Fully-Firstable Anagram Sets
How can I fix/modify my tub/shower combo so the water comes out of the showerhead?
How could indestructible materials be used in power generation?
Does a druid starting with a bow start with no arrows?
AES: Why is it a good practice to use only the first 16bytes of a hash for encryption?
What about the virus in 12 Monkeys?
How can I prevent hyper evolved versions of regular creatures from wiping out their cousins?
Will google still index a page if I use a $_SESSION variable?
Is it possible to run Internet Explorer on OS X El Capitan?
How to draw the figure with four pentagons?
What's the point of deactivating Num Lock on login screens?
What is the most common color to indicate the input-field is disabled?
I'm flying to France today and my passport expires in less than 2 months
Can a virus destroy the BIOS of a modern computer?
Is it legal for company to use my work email to pretend I still work there?
What is the word for reserving something for yourself before others do?
I Accidentally Deleted a Stock Terminal Theme
Anagram holiday
Is there a hemisphere-neutral way of specifying a season?
What to put in ESTA if staying in US for a few days before going on to Canada
How can saying a song's name be a copyright violation?
Implementing a queue: questions and clarification
Thread-safe queueSTL queue implementationArray-like container for uints shorter than 8 bits (Rev 1)Queue with std::vectorAsynchronously load and unload a queueLockless SCSP queueUpdatable priority queueFixed Size QueueImplementation of a queueimplementing a queue using std::vector
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;
$begingroup$
Im trying to teach myself some computer science (and c++). I am relatively new to this (and to code review).
I have attempted to implement a queue. I have copied the code below for reference.
QUESTIONS:
I used the template described on cppreference.com to guide me in the implementation of some of the functions, such as push() (enqueue() in my case). On cppreference.com, the following templates are given:
(a) push(const value_type & value);
(b) push(value_type && value);
https://en.cppreference.com/w/cpp/container/queue/push
Since (a) takes a reference, how is it that literals are added to the queue?
Moreover, if I implement a function
enqueue(Queue const & other)
using the function
enqueue(T const & value)
by iterating through "other" and enqueuing every value in "other," will this not add "deep" copies of the values in "other?" And, therefore, I should not pass a reference to other, but a copy?
Moreover, what is the meaning of "&&"?
How are the two functions
(a) const T & front() const
(b) T & front()
differentiated by the compiler? Moreover, that (a) has a const after the function's name means that an outside user will not be able to modify the front variable? Would you even want to modify the front (or end) variable of a queue?
I have used assertions in many instances: I assert that the size must be non-zero when accessing the front or the back and when popping (or, dequeueing in my case); I assert that an index must be between 0 and one less than the size when implementing the function
T const & at(size_t index)
and I assert that "this != other" in the copy constructor. Are these appropriate uses of assert? Should I throw exceptions instead? Or should I do things differently?
Would you implement the copy constructor and the destructor differently?
Queue(Queue const & other) : m_front(nullptr),
m_back(nullptr),
m_size(0),
m_cap(other.m_cap)
assert(this != &other);
this->enqueue(other);
~Queue()
this->clear();
I noticed that cppreference mentioned something about an "Allocator." Would it be difficult to incorporate into my code? Is it only for array-based implementations? I have implemented queues via arrays. If it is not difficult to incorporate, how would I go about doing so?
The following questions are welcomed as well. However, I realize they are non specific, and if I should remove them, please let me know. I will do so, and restrict the code I posted to reflect only my questions prior.
- Should I have implemented anything differently?
- Any stylistic advice?
MY CODE (FOR REFERENCE):
Queue.h:
#ifndef QUEUE_H
#define QUEUE_H
#include <algorithm>
#include <climits>
template <class T>
class Queue
private:
struct QueueItem
T val;
QueueItem *next;
QueueItem() : next(nullptr)
QueueItem(T const & val, QueueItem *next) : val(val), next(next)
QueueItem(T const & val) : val(val), next(nullptr)
QueueItem(QueueItem *next) : next(next)
;
QueueItem *m_front;
QueueItem *m_back;
size_t m_size;
size_t m_cap;
public:
//friends
friend void swap(Queue & a, Queue & b)
using std::swap;
swap(a.m_front, b.m_front);
swap(a.m_back, b.m_back);
swap(a.m_size, b.m_size);
swap(a.m_cap, b.m_cap);
friend void concatenate(Queue & a, Queue & b)
a.m_back->next = b.m_front;
a.m_back = b.m_back;
//constructors and deconstructor
Queue() : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(INT_MAX)
Queue(size_t const cap) : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(cap)
assert(cap > 0);
Queue(Queue const & other) : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(other.m_cap)
assert(this != &other);
this->enqueue(other);
~Queue()
this->clear();
//capacity
size_t const size() const;
bool const empty() const;
size_t const capacity() const;
bool const at_capacity() const;
//element access
T & front();
T const & front() const;
T & back();
T const & back() const;
bool const has(T const & val) const;
T & at(size_t index);
T const & at(size_t index) const;
T & operator [] (size_t index);
T const & operator [] (size_t index) const;
T const * const data() const;
//modifiers
T const dequeue();
T const enqueue(T const & val);
T const enqueue(T && val);
void enqueue(Queue const & other);
T const deenqueue(T const & val);
T const deenqueue(T && val);
void reverse();
void clear();
Queue & operator + (Queue const & other);
Queue & operator += (Queue const & other);
Queue & operator = (Queue const other);
//comparators
bool const operator == (Queue const & other);
bool const operator != (Queue const & other);
;
#include "Queue.hpp"
#endif // QUEUE_H
List.hpp
#ifndef QUEUE_HPP
#define QUEUE_HPP
//capacity
template <class T>
size_t const Queue<T>::size() const
return m_size;
template <class T>
bool const Queue<T>::empty() const
return m_size == 0;
template <class T>
size_t const Queue<T>::capacity() const
return m_cap;
template <class T>
bool const Queue<T>::at_capacity() const
return m_size == m_cap;
//element access
template <class T>
T & Queue<T>::front()
assert(m_size > 0);
return m_front->val;
template <class T>
T const & Queue<T>::front() const
assert(m_size > 0);
return m_front->val;
template <class T>
T & Queue<T>::back()
assert(m_size > 0);
return m_back->val;
template <class T>
T const & Queue<T>::back() const
assert(m_size > 0);
return m_back->val;
template <class T>
bool const Queue<T>::has(T const & val) const
QueueItem *item = m_front;
while(item)
if(item->val == val)
return true;
item = item->next;
return false;
template <class T>
T & Queue<T>::at(size_t index)
assert(index > -1 && index < m_size);
QueueItem *item = m_front;
while(index-- > 0)
item = item->next;
return item->val;
template <class T>
T const & Queue<T>::at(size_t index) const
assert(index > -1 && index < m_size);
QueueItem *item = m_front;
while(index-- > 0)
item = item->next;
return item->val;
template <class T>
T & Queue<T>::operator [] (size_t index)
return at(index);
template <class T>
T const & Queue<T>::operator [] (size_t index) const
return at(index);
template <class T>
T const * const Queue<T>::data() const
if(m_size == 0)
return nullptr;
T const * const data = new T[m_size];
QueueItem *item = m_front;
for(size_t i = 0; item; item = item->next)
data[i++] = item->val;
return data;
//modifiers
template <class T>
T const Queue<T>::dequeue()
assert(m_size > 0);
T const give = m_front->val;
QueueItem *item = m_front->next;
delete m_front;
m_front = item;
--m_size;
if(m_size == 0)
m_back = nullptr;
return give;
template <class T>
T const Queue<T>::enqueue(T const & val)
T const give;
if(m_size == m_cap)
give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
T const Queue<T>::enqueue(T && val)
T const give;
if(m_size == m_cap)
give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
void Queue<T>::enqueue(Queue<T> const & other)
QueueItem *item = other.m_front;
while(item)
this->enqueue(item->val);
item = item->next;
template <class T>
T const Queue<T>::deenqueue(T const & val)
T const give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
T const Queue<T>::deenqueue(T && val)
T const give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
void Queue<T>::reverse()
using std::swap;
QueueItem *first = nullptr,
*second = m_front,
*save;
while(second)
save = second->next;
second->next = first;
first = second;
second = save;
swap(m_front, m_back);
template <class T>
void Queue<T>::clear()
while(m_front)
QueueItem *item = m_front->next;
delete m_front;
m_front = item;
m_back = nullptr;
m_size = 0;
template <class T>
Queue<T> & Queue<T>::operator + (Queue<T> const & other)
this->enqueue(other);
return *this;
template <class T>
Queue<T> & Queue<T>::operator += (Queue<T> const & other)
this->enqueue(other);
return *this;
template <class T>
Queue<T> & Queue<T>::operator = (Queue<T> const other)
swap(*this, other);
return *this;
//comparators
template <class T>
bool const Queue<T>::operator == (Queue<T> const & other)
if(m_size != other.m_size)
return false;
QueueItem *thsitem = m_front,
*othitem = other.m_front;
while(thsitem)
if(thsitem->val != othitem->val)
return false;
thsitem = thsitem->next;
othitem = othitem->next;
return true;
template <class T>
bool const Queue<T>::operator != (Queue<T> const & other)
return !(*this == other);
#endif // QUEUE_HPP
c++ object-oriented c++11 queue
New contributor
$endgroup$
add a comment |
$begingroup$
Im trying to teach myself some computer science (and c++). I am relatively new to this (and to code review).
I have attempted to implement a queue. I have copied the code below for reference.
QUESTIONS:
I used the template described on cppreference.com to guide me in the implementation of some of the functions, such as push() (enqueue() in my case). On cppreference.com, the following templates are given:
(a) push(const value_type & value);
(b) push(value_type && value);
https://en.cppreference.com/w/cpp/container/queue/push
Since (a) takes a reference, how is it that literals are added to the queue?
Moreover, if I implement a function
enqueue(Queue const & other)
using the function
enqueue(T const & value)
by iterating through "other" and enqueuing every value in "other," will this not add "deep" copies of the values in "other?" And, therefore, I should not pass a reference to other, but a copy?
Moreover, what is the meaning of "&&"?
How are the two functions
(a) const T & front() const
(b) T & front()
differentiated by the compiler? Moreover, that (a) has a const after the function's name means that an outside user will not be able to modify the front variable? Would you even want to modify the front (or end) variable of a queue?
I have used assertions in many instances: I assert that the size must be non-zero when accessing the front or the back and when popping (or, dequeueing in my case); I assert that an index must be between 0 and one less than the size when implementing the function
T const & at(size_t index)
and I assert that "this != other" in the copy constructor. Are these appropriate uses of assert? Should I throw exceptions instead? Or should I do things differently?
Would you implement the copy constructor and the destructor differently?
Queue(Queue const & other) : m_front(nullptr),
m_back(nullptr),
m_size(0),
m_cap(other.m_cap)
assert(this != &other);
this->enqueue(other);
~Queue()
this->clear();
I noticed that cppreference mentioned something about an "Allocator." Would it be difficult to incorporate into my code? Is it only for array-based implementations? I have implemented queues via arrays. If it is not difficult to incorporate, how would I go about doing so?
The following questions are welcomed as well. However, I realize they are non specific, and if I should remove them, please let me know. I will do so, and restrict the code I posted to reflect only my questions prior.
- Should I have implemented anything differently?
- Any stylistic advice?
MY CODE (FOR REFERENCE):
Queue.h:
#ifndef QUEUE_H
#define QUEUE_H
#include <algorithm>
#include <climits>
template <class T>
class Queue
private:
struct QueueItem
T val;
QueueItem *next;
QueueItem() : next(nullptr)
QueueItem(T const & val, QueueItem *next) : val(val), next(next)
QueueItem(T const & val) : val(val), next(nullptr)
QueueItem(QueueItem *next) : next(next)
;
QueueItem *m_front;
QueueItem *m_back;
size_t m_size;
size_t m_cap;
public:
//friends
friend void swap(Queue & a, Queue & b)
using std::swap;
swap(a.m_front, b.m_front);
swap(a.m_back, b.m_back);
swap(a.m_size, b.m_size);
swap(a.m_cap, b.m_cap);
friend void concatenate(Queue & a, Queue & b)
a.m_back->next = b.m_front;
a.m_back = b.m_back;
//constructors and deconstructor
Queue() : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(INT_MAX)
Queue(size_t const cap) : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(cap)
assert(cap > 0);
Queue(Queue const & other) : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(other.m_cap)
assert(this != &other);
this->enqueue(other);
~Queue()
this->clear();
//capacity
size_t const size() const;
bool const empty() const;
size_t const capacity() const;
bool const at_capacity() const;
//element access
T & front();
T const & front() const;
T & back();
T const & back() const;
bool const has(T const & val) const;
T & at(size_t index);
T const & at(size_t index) const;
T & operator [] (size_t index);
T const & operator [] (size_t index) const;
T const * const data() const;
//modifiers
T const dequeue();
T const enqueue(T const & val);
T const enqueue(T && val);
void enqueue(Queue const & other);
T const deenqueue(T const & val);
T const deenqueue(T && val);
void reverse();
void clear();
Queue & operator + (Queue const & other);
Queue & operator += (Queue const & other);
Queue & operator = (Queue const other);
//comparators
bool const operator == (Queue const & other);
bool const operator != (Queue const & other);
;
#include "Queue.hpp"
#endif // QUEUE_H
List.hpp
#ifndef QUEUE_HPP
#define QUEUE_HPP
//capacity
template <class T>
size_t const Queue<T>::size() const
return m_size;
template <class T>
bool const Queue<T>::empty() const
return m_size == 0;
template <class T>
size_t const Queue<T>::capacity() const
return m_cap;
template <class T>
bool const Queue<T>::at_capacity() const
return m_size == m_cap;
//element access
template <class T>
T & Queue<T>::front()
assert(m_size > 0);
return m_front->val;
template <class T>
T const & Queue<T>::front() const
assert(m_size > 0);
return m_front->val;
template <class T>
T & Queue<T>::back()
assert(m_size > 0);
return m_back->val;
template <class T>
T const & Queue<T>::back() const
assert(m_size > 0);
return m_back->val;
template <class T>
bool const Queue<T>::has(T const & val) const
QueueItem *item = m_front;
while(item)
if(item->val == val)
return true;
item = item->next;
return false;
template <class T>
T & Queue<T>::at(size_t index)
assert(index > -1 && index < m_size);
QueueItem *item = m_front;
while(index-- > 0)
item = item->next;
return item->val;
template <class T>
T const & Queue<T>::at(size_t index) const
assert(index > -1 && index < m_size);
QueueItem *item = m_front;
while(index-- > 0)
item = item->next;
return item->val;
template <class T>
T & Queue<T>::operator [] (size_t index)
return at(index);
template <class T>
T const & Queue<T>::operator [] (size_t index) const
return at(index);
template <class T>
T const * const Queue<T>::data() const
if(m_size == 0)
return nullptr;
T const * const data = new T[m_size];
QueueItem *item = m_front;
for(size_t i = 0; item; item = item->next)
data[i++] = item->val;
return data;
//modifiers
template <class T>
T const Queue<T>::dequeue()
assert(m_size > 0);
T const give = m_front->val;
QueueItem *item = m_front->next;
delete m_front;
m_front = item;
--m_size;
if(m_size == 0)
m_back = nullptr;
return give;
template <class T>
T const Queue<T>::enqueue(T const & val)
T const give;
if(m_size == m_cap)
give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
T const Queue<T>::enqueue(T && val)
T const give;
if(m_size == m_cap)
give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
void Queue<T>::enqueue(Queue<T> const & other)
QueueItem *item = other.m_front;
while(item)
this->enqueue(item->val);
item = item->next;
template <class T>
T const Queue<T>::deenqueue(T const & val)
T const give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
T const Queue<T>::deenqueue(T && val)
T const give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
void Queue<T>::reverse()
using std::swap;
QueueItem *first = nullptr,
*second = m_front,
*save;
while(second)
save = second->next;
second->next = first;
first = second;
second = save;
swap(m_front, m_back);
template <class T>
void Queue<T>::clear()
while(m_front)
QueueItem *item = m_front->next;
delete m_front;
m_front = item;
m_back = nullptr;
m_size = 0;
template <class T>
Queue<T> & Queue<T>::operator + (Queue<T> const & other)
this->enqueue(other);
return *this;
template <class T>
Queue<T> & Queue<T>::operator += (Queue<T> const & other)
this->enqueue(other);
return *this;
template <class T>
Queue<T> & Queue<T>::operator = (Queue<T> const other)
swap(*this, other);
return *this;
//comparators
template <class T>
bool const Queue<T>::operator == (Queue<T> const & other)
if(m_size != other.m_size)
return false;
QueueItem *thsitem = m_front,
*othitem = other.m_front;
while(thsitem)
if(thsitem->val != othitem->val)
return false;
thsitem = thsitem->next;
othitem = othitem->next;
return true;
template <class T>
bool const Queue<T>::operator != (Queue<T> const & other)
return !(*this == other);
#endif // QUEUE_HPP
c++ object-oriented c++11 queue
New contributor
$endgroup$
add a comment |
$begingroup$
Im trying to teach myself some computer science (and c++). I am relatively new to this (and to code review).
I have attempted to implement a queue. I have copied the code below for reference.
QUESTIONS:
I used the template described on cppreference.com to guide me in the implementation of some of the functions, such as push() (enqueue() in my case). On cppreference.com, the following templates are given:
(a) push(const value_type & value);
(b) push(value_type && value);
https://en.cppreference.com/w/cpp/container/queue/push
Since (a) takes a reference, how is it that literals are added to the queue?
Moreover, if I implement a function
enqueue(Queue const & other)
using the function
enqueue(T const & value)
by iterating through "other" and enqueuing every value in "other," will this not add "deep" copies of the values in "other?" And, therefore, I should not pass a reference to other, but a copy?
Moreover, what is the meaning of "&&"?
How are the two functions
(a) const T & front() const
(b) T & front()
differentiated by the compiler? Moreover, that (a) has a const after the function's name means that an outside user will not be able to modify the front variable? Would you even want to modify the front (or end) variable of a queue?
I have used assertions in many instances: I assert that the size must be non-zero when accessing the front or the back and when popping (or, dequeueing in my case); I assert that an index must be between 0 and one less than the size when implementing the function
T const & at(size_t index)
and I assert that "this != other" in the copy constructor. Are these appropriate uses of assert? Should I throw exceptions instead? Or should I do things differently?
Would you implement the copy constructor and the destructor differently?
Queue(Queue const & other) : m_front(nullptr),
m_back(nullptr),
m_size(0),
m_cap(other.m_cap)
assert(this != &other);
this->enqueue(other);
~Queue()
this->clear();
I noticed that cppreference mentioned something about an "Allocator." Would it be difficult to incorporate into my code? Is it only for array-based implementations? I have implemented queues via arrays. If it is not difficult to incorporate, how would I go about doing so?
The following questions are welcomed as well. However, I realize they are non specific, and if I should remove them, please let me know. I will do so, and restrict the code I posted to reflect only my questions prior.
- Should I have implemented anything differently?
- Any stylistic advice?
MY CODE (FOR REFERENCE):
Queue.h:
#ifndef QUEUE_H
#define QUEUE_H
#include <algorithm>
#include <climits>
template <class T>
class Queue
private:
struct QueueItem
T val;
QueueItem *next;
QueueItem() : next(nullptr)
QueueItem(T const & val, QueueItem *next) : val(val), next(next)
QueueItem(T const & val) : val(val), next(nullptr)
QueueItem(QueueItem *next) : next(next)
;
QueueItem *m_front;
QueueItem *m_back;
size_t m_size;
size_t m_cap;
public:
//friends
friend void swap(Queue & a, Queue & b)
using std::swap;
swap(a.m_front, b.m_front);
swap(a.m_back, b.m_back);
swap(a.m_size, b.m_size);
swap(a.m_cap, b.m_cap);
friend void concatenate(Queue & a, Queue & b)
a.m_back->next = b.m_front;
a.m_back = b.m_back;
//constructors and deconstructor
Queue() : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(INT_MAX)
Queue(size_t const cap) : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(cap)
assert(cap > 0);
Queue(Queue const & other) : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(other.m_cap)
assert(this != &other);
this->enqueue(other);
~Queue()
this->clear();
//capacity
size_t const size() const;
bool const empty() const;
size_t const capacity() const;
bool const at_capacity() const;
//element access
T & front();
T const & front() const;
T & back();
T const & back() const;
bool const has(T const & val) const;
T & at(size_t index);
T const & at(size_t index) const;
T & operator [] (size_t index);
T const & operator [] (size_t index) const;
T const * const data() const;
//modifiers
T const dequeue();
T const enqueue(T const & val);
T const enqueue(T && val);
void enqueue(Queue const & other);
T const deenqueue(T const & val);
T const deenqueue(T && val);
void reverse();
void clear();
Queue & operator + (Queue const & other);
Queue & operator += (Queue const & other);
Queue & operator = (Queue const other);
//comparators
bool const operator == (Queue const & other);
bool const operator != (Queue const & other);
;
#include "Queue.hpp"
#endif // QUEUE_H
List.hpp
#ifndef QUEUE_HPP
#define QUEUE_HPP
//capacity
template <class T>
size_t const Queue<T>::size() const
return m_size;
template <class T>
bool const Queue<T>::empty() const
return m_size == 0;
template <class T>
size_t const Queue<T>::capacity() const
return m_cap;
template <class T>
bool const Queue<T>::at_capacity() const
return m_size == m_cap;
//element access
template <class T>
T & Queue<T>::front()
assert(m_size > 0);
return m_front->val;
template <class T>
T const & Queue<T>::front() const
assert(m_size > 0);
return m_front->val;
template <class T>
T & Queue<T>::back()
assert(m_size > 0);
return m_back->val;
template <class T>
T const & Queue<T>::back() const
assert(m_size > 0);
return m_back->val;
template <class T>
bool const Queue<T>::has(T const & val) const
QueueItem *item = m_front;
while(item)
if(item->val == val)
return true;
item = item->next;
return false;
template <class T>
T & Queue<T>::at(size_t index)
assert(index > -1 && index < m_size);
QueueItem *item = m_front;
while(index-- > 0)
item = item->next;
return item->val;
template <class T>
T const & Queue<T>::at(size_t index) const
assert(index > -1 && index < m_size);
QueueItem *item = m_front;
while(index-- > 0)
item = item->next;
return item->val;
template <class T>
T & Queue<T>::operator [] (size_t index)
return at(index);
template <class T>
T const & Queue<T>::operator [] (size_t index) const
return at(index);
template <class T>
T const * const Queue<T>::data() const
if(m_size == 0)
return nullptr;
T const * const data = new T[m_size];
QueueItem *item = m_front;
for(size_t i = 0; item; item = item->next)
data[i++] = item->val;
return data;
//modifiers
template <class T>
T const Queue<T>::dequeue()
assert(m_size > 0);
T const give = m_front->val;
QueueItem *item = m_front->next;
delete m_front;
m_front = item;
--m_size;
if(m_size == 0)
m_back = nullptr;
return give;
template <class T>
T const Queue<T>::enqueue(T const & val)
T const give;
if(m_size == m_cap)
give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
T const Queue<T>::enqueue(T && val)
T const give;
if(m_size == m_cap)
give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
void Queue<T>::enqueue(Queue<T> const & other)
QueueItem *item = other.m_front;
while(item)
this->enqueue(item->val);
item = item->next;
template <class T>
T const Queue<T>::deenqueue(T const & val)
T const give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
T const Queue<T>::deenqueue(T && val)
T const give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
void Queue<T>::reverse()
using std::swap;
QueueItem *first = nullptr,
*second = m_front,
*save;
while(second)
save = second->next;
second->next = first;
first = second;
second = save;
swap(m_front, m_back);
template <class T>
void Queue<T>::clear()
while(m_front)
QueueItem *item = m_front->next;
delete m_front;
m_front = item;
m_back = nullptr;
m_size = 0;
template <class T>
Queue<T> & Queue<T>::operator + (Queue<T> const & other)
this->enqueue(other);
return *this;
template <class T>
Queue<T> & Queue<T>::operator += (Queue<T> const & other)
this->enqueue(other);
return *this;
template <class T>
Queue<T> & Queue<T>::operator = (Queue<T> const other)
swap(*this, other);
return *this;
//comparators
template <class T>
bool const Queue<T>::operator == (Queue<T> const & other)
if(m_size != other.m_size)
return false;
QueueItem *thsitem = m_front,
*othitem = other.m_front;
while(thsitem)
if(thsitem->val != othitem->val)
return false;
thsitem = thsitem->next;
othitem = othitem->next;
return true;
template <class T>
bool const Queue<T>::operator != (Queue<T> const & other)
return !(*this == other);
#endif // QUEUE_HPP
c++ object-oriented c++11 queue
New contributor
$endgroup$
Im trying to teach myself some computer science (and c++). I am relatively new to this (and to code review).
I have attempted to implement a queue. I have copied the code below for reference.
QUESTIONS:
I used the template described on cppreference.com to guide me in the implementation of some of the functions, such as push() (enqueue() in my case). On cppreference.com, the following templates are given:
(a) push(const value_type & value);
(b) push(value_type && value);
https://en.cppreference.com/w/cpp/container/queue/push
Since (a) takes a reference, how is it that literals are added to the queue?
Moreover, if I implement a function
enqueue(Queue const & other)
using the function
enqueue(T const & value)
by iterating through "other" and enqueuing every value in "other," will this not add "deep" copies of the values in "other?" And, therefore, I should not pass a reference to other, but a copy?
Moreover, what is the meaning of "&&"?
How are the two functions
(a) const T & front() const
(b) T & front()
differentiated by the compiler? Moreover, that (a) has a const after the function's name means that an outside user will not be able to modify the front variable? Would you even want to modify the front (or end) variable of a queue?
I have used assertions in many instances: I assert that the size must be non-zero when accessing the front or the back and when popping (or, dequeueing in my case); I assert that an index must be between 0 and one less than the size when implementing the function
T const & at(size_t index)
and I assert that "this != other" in the copy constructor. Are these appropriate uses of assert? Should I throw exceptions instead? Or should I do things differently?
Would you implement the copy constructor and the destructor differently?
Queue(Queue const & other) : m_front(nullptr),
m_back(nullptr),
m_size(0),
m_cap(other.m_cap)
assert(this != &other);
this->enqueue(other);
~Queue()
this->clear();
I noticed that cppreference mentioned something about an "Allocator." Would it be difficult to incorporate into my code? Is it only for array-based implementations? I have implemented queues via arrays. If it is not difficult to incorporate, how would I go about doing so?
The following questions are welcomed as well. However, I realize they are non specific, and if I should remove them, please let me know. I will do so, and restrict the code I posted to reflect only my questions prior.
- Should I have implemented anything differently?
- Any stylistic advice?
MY CODE (FOR REFERENCE):
Queue.h:
#ifndef QUEUE_H
#define QUEUE_H
#include <algorithm>
#include <climits>
template <class T>
class Queue
private:
struct QueueItem
T val;
QueueItem *next;
QueueItem() : next(nullptr)
QueueItem(T const & val, QueueItem *next) : val(val), next(next)
QueueItem(T const & val) : val(val), next(nullptr)
QueueItem(QueueItem *next) : next(next)
;
QueueItem *m_front;
QueueItem *m_back;
size_t m_size;
size_t m_cap;
public:
//friends
friend void swap(Queue & a, Queue & b)
using std::swap;
swap(a.m_front, b.m_front);
swap(a.m_back, b.m_back);
swap(a.m_size, b.m_size);
swap(a.m_cap, b.m_cap);
friend void concatenate(Queue & a, Queue & b)
a.m_back->next = b.m_front;
a.m_back = b.m_back;
//constructors and deconstructor
Queue() : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(INT_MAX)
Queue(size_t const cap) : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(cap)
assert(cap > 0);
Queue(Queue const & other) : m_front(nullptr), m_back(nullptr), m_size(0), m_cap(other.m_cap)
assert(this != &other);
this->enqueue(other);
~Queue()
this->clear();
//capacity
size_t const size() const;
bool const empty() const;
size_t const capacity() const;
bool const at_capacity() const;
//element access
T & front();
T const & front() const;
T & back();
T const & back() const;
bool const has(T const & val) const;
T & at(size_t index);
T const & at(size_t index) const;
T & operator [] (size_t index);
T const & operator [] (size_t index) const;
T const * const data() const;
//modifiers
T const dequeue();
T const enqueue(T const & val);
T const enqueue(T && val);
void enqueue(Queue const & other);
T const deenqueue(T const & val);
T const deenqueue(T && val);
void reverse();
void clear();
Queue & operator + (Queue const & other);
Queue & operator += (Queue const & other);
Queue & operator = (Queue const other);
//comparators
bool const operator == (Queue const & other);
bool const operator != (Queue const & other);
;
#include "Queue.hpp"
#endif // QUEUE_H
List.hpp
#ifndef QUEUE_HPP
#define QUEUE_HPP
//capacity
template <class T>
size_t const Queue<T>::size() const
return m_size;
template <class T>
bool const Queue<T>::empty() const
return m_size == 0;
template <class T>
size_t const Queue<T>::capacity() const
return m_cap;
template <class T>
bool const Queue<T>::at_capacity() const
return m_size == m_cap;
//element access
template <class T>
T & Queue<T>::front()
assert(m_size > 0);
return m_front->val;
template <class T>
T const & Queue<T>::front() const
assert(m_size > 0);
return m_front->val;
template <class T>
T & Queue<T>::back()
assert(m_size > 0);
return m_back->val;
template <class T>
T const & Queue<T>::back() const
assert(m_size > 0);
return m_back->val;
template <class T>
bool const Queue<T>::has(T const & val) const
QueueItem *item = m_front;
while(item)
if(item->val == val)
return true;
item = item->next;
return false;
template <class T>
T & Queue<T>::at(size_t index)
assert(index > -1 && index < m_size);
QueueItem *item = m_front;
while(index-- > 0)
item = item->next;
return item->val;
template <class T>
T const & Queue<T>::at(size_t index) const
assert(index > -1 && index < m_size);
QueueItem *item = m_front;
while(index-- > 0)
item = item->next;
return item->val;
template <class T>
T & Queue<T>::operator [] (size_t index)
return at(index);
template <class T>
T const & Queue<T>::operator [] (size_t index) const
return at(index);
template <class T>
T const * const Queue<T>::data() const
if(m_size == 0)
return nullptr;
T const * const data = new T[m_size];
QueueItem *item = m_front;
for(size_t i = 0; item; item = item->next)
data[i++] = item->val;
return data;
//modifiers
template <class T>
T const Queue<T>::dequeue()
assert(m_size > 0);
T const give = m_front->val;
QueueItem *item = m_front->next;
delete m_front;
m_front = item;
--m_size;
if(m_size == 0)
m_back = nullptr;
return give;
template <class T>
T const Queue<T>::enqueue(T const & val)
T const give;
if(m_size == m_cap)
give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
T const Queue<T>::enqueue(T && val)
T const give;
if(m_size == m_cap)
give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
void Queue<T>::enqueue(Queue<T> const & other)
QueueItem *item = other.m_front;
while(item)
this->enqueue(item->val);
item = item->next;
template <class T>
T const Queue<T>::deenqueue(T const & val)
T const give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
T const Queue<T>::deenqueue(T && val)
T const give = dequeue();
QueueItem *item = new QueueItem(val);
if(m_size == 0)
m_front = m_back = item;
else
m_back->next = item;
m_back = item;
++m_size;
return give;
template <class T>
void Queue<T>::reverse()
using std::swap;
QueueItem *first = nullptr,
*second = m_front,
*save;
while(second)
save = second->next;
second->next = first;
first = second;
second = save;
swap(m_front, m_back);
template <class T>
void Queue<T>::clear()
while(m_front)
QueueItem *item = m_front->next;
delete m_front;
m_front = item;
m_back = nullptr;
m_size = 0;
template <class T>
Queue<T> & Queue<T>::operator + (Queue<T> const & other)
this->enqueue(other);
return *this;
template <class T>
Queue<T> & Queue<T>::operator += (Queue<T> const & other)
this->enqueue(other);
return *this;
template <class T>
Queue<T> & Queue<T>::operator = (Queue<T> const other)
swap(*this, other);
return *this;
//comparators
template <class T>
bool const Queue<T>::operator == (Queue<T> const & other)
if(m_size != other.m_size)
return false;
QueueItem *thsitem = m_front,
*othitem = other.m_front;
while(thsitem)
if(thsitem->val != othitem->val)
return false;
thsitem = thsitem->next;
othitem = othitem->next;
return true;
template <class T>
bool const Queue<T>::operator != (Queue<T> const & other)
return !(*this == other);
#endif // QUEUE_HPP
c++ object-oriented c++11 queue
c++ object-oriented c++11 queue
New contributor
New contributor
New contributor
asked 11 mins ago
Rafael VergnaudRafael Vergnaud
101
101
New contributor
New contributor
add a comment |
add a comment |
0
active
oldest
votes
Your Answer
StackExchange.ifUsing("editor", function ()
return StackExchange.using("mathjaxEditing", function ()
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
);
);
, "mathjax-editing");
StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");
StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);
else
createEditor();
);
function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);
);
Rafael Vergnaud is a new contributor. Be nice, and check out our Code of Conduct.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216902%2fimplementing-a-queue-questions-and-clarification%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
0
active
oldest
votes
0
active
oldest
votes
active
oldest
votes
active
oldest
votes
Rafael Vergnaud is a new contributor. Be nice, and check out our Code of Conduct.
Rafael Vergnaud is a new contributor. Be nice, and check out our Code of Conduct.
Rafael Vergnaud is a new contributor. Be nice, and check out our Code of Conduct.
Rafael Vergnaud is a new contributor. Be nice, and check out our Code of Conduct.
Thanks for contributing an answer to Code Review Stack Exchange!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
Use MathJax to format equations. MathJax reference.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216902%2fimplementing-a-queue-questions-and-clarification%23new-answer', 'question_page');
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown