Solving your issue
Your problem is that you assumed incorrect operator precedence. Since modulo division (%) has higher precedence (priority) than addition (+) your expression
rear + 1 % size
is not evaluated as (you assumed)
(rear + 1) % size
but
rear + (1 % size)
If you apply parenthesis to ensure increment to be calculated first only after then the modulo division then your code works correctly (2nd code snippet).
And a bit more...
I took some time to enhance your code.
- added a destructor to properly free the resources
- used initialization list in the constructor
- did some name refactoring on the code (functions to follow upper CamelCase, some names changed, etc)
- made functions constant when they do not change the instance
- used generics to allow the RingBuffer to store any arbitrary type
- used throw to indicate errors (such as full/empty RingBuffer when trying to enqueue/dequeue)
So here's the enhanced version of mine:
#include <iostream>
#include <stdexcept>
template <typename X> class RingBuffer
{
private:
size_t _size;
int _front;
int _rear;
X * _elements;
public:
RingBuffer(size_t size) :
_size(size),
_front(-1),
_rear(-1),
_elements(new X[size])
{ }
~RingBuffer() { delete[] _elements; }
bool IsFull() const { return (_rear + 1) % (int)_size == _front; }
bool IsEmpty() const { return _front == -1; }
void Enqueue(X x)
{
if (IsFull())
throw std::runtime_error("RingBUffer is full");
if (IsEmpty())
{
_rear = 0;
_front = 0;
}
else
{
_rear = (_rear + 1) % _size;
}
_elements[_rear] = x;
}
X Dequeue()
{
if (IsEmpty())
throw std::runtime_error("RingBUffer is empty");
int index = _front;
if (_front == _rear)
{
_front = -1;
_rear = -1;
}
else
{
_front = (_front + 1) % _size;
}
return _elements[index];
}
void PrintElement(int i) const
{
if (i != _front)
std::cout << ", ";
std::cout << _elements[i];
}
void Display() const
{
if (IsEmpty())
{
std::cout << "RingBuffer is empty." << std::endl;
return;
}
for (int i = _front; i != _rear; i = (i + 1) % _size)
PrintElement(i);
PrintElement(_rear);
std::cout << std::endl;
}
};
int main()
{
RingBuffer<int> ringBuffer(5);
try
{
ringBuffer.Dequeue();
}
catch (const std::runtime_error & error)
{
std::cerr << error.what() << std::endl;
}
ringBuffer.Enqueue(1);
ringBuffer.Enqueue(2);
ringBuffer.Enqueue(3);
ringBuffer.Enqueue(4);
ringBuffer.Enqueue(5);
// inserted 5 elements
try
{
ringBuffer.Enqueue(6); // trying to insert 6th element, RingBuffer is full
}
catch (const std::runtime_error & error)
{
std::cerr << error.what() << std::endl;
}
try
{
ringBuffer.Enqueue(7);
}
catch (const std::runtime_error & error)
{
std::cerr << error.what() << std::endl;
}
ringBuffer.Display();
ringBuffer.Dequeue();
ringBuffer.Dequeue();
ringBuffer.Dequeue();
ringBuffer.Display();
ringBuffer.Enqueue(200);
ringBuffer.Enqueue(201);
ringBuffer.Enqueue(203);
ringBuffer.Display();
return 0;
}