When this situation occurs, your queue is full. You have a few options when to deal with new items that can be pushed:
discard the pushed event: only when some other item is popped can now items be pushed again. Neither head
nor tail
is updated.
Example: Think of an event queue that has filled up, new requests are simple ignored.
discard (pop) the oldest event on the queue: in this case you update both the head
and tail
pointer one place.
Example: buffering incomming image frames from a webcam for processing. For a 'live' feed you may prefer to discard the older frames when the processing has a hickup.
create a bigger queue: that is, allocate more memory on the fly
Example: you use a circular queue since it an efficient implementation that doesn't require memory allocation most of the time when you push items. However, you do not want to loose items on the queue so you allow reallocating more memory once in a while
What the right action is depends on your application.
PS.: Your implementation is based on keeping an empty slot in your queue to distinguish full and empty buffer. Another option is to keep a counter on the number of elements in your queue to make this distinction. More info can be found on Circular buffer (Wikipedia).