Open In App

How to Implement a Circular Buffer Using std::vector?

Last Updated : 03 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

A circular buffer, also known as a cyclic buffer or ring buffer, is a data structure that uses a single, fixed-size buffer as if it were connected end-to-end. In this article, we will learn how to implement a circular buffer in C++ using vector.

Implementing Circular Buffer Using Vector

We can implement a circular buffer using std::vector that provides a flexible and dynamic array to manage data in a FIFO (First-In-First-Out) manner efficiently using the below approach:

Base Design

  • Define a std::vector to hold the elements of the circular buffer and a variable capacity that denotes the maximum size of the circular buffer. The actual capacity is set to capacity + 1 to distinguish between full and empty buffer states.
  • Maintain two indexes front and back pointing at the start and end of the buffer.
  • Increment the indexes using modulo operator (%) such that whenever it is about to go over the size of the array, it will move back to the start. We can do it using the formula: front = (front + 1) % capacity;

The basic operations are then implemented using the following logic:

Insertion (push_back)

Add elements at the back using back index. There are two possibilities:

  • If the buffer is not full, add an element at the back position and increment it.
  • If the buffer is full, throw the overflow exception.

Deletion (pop_front)

Remove elements from the front using front index: There are two possibilities:

  • If the buffer is not empty, logically remove the element from the front by incrementing front pointer in a circular manner.
  • If the buffer is empty, throw the underflow exception.

Access Front Element (getFront)

  • If the buffer is empty, return out_of_range exception.
  • If not, return the element at index front.

Access Back Element (getBack)

  • If the buffer is empty, return out_of_range exception.
  • If not, return the element at index back - 1. But if the back is 0, then we have to move back to the end of the buffer and return element at index capacity - 1.

Check if Buffer is Empty (empty)

Implement a function empty() to check if the circular buffer is empty or not. If both the front and back are equal and, then the circular buffer is empty.

Check if Buffer is Full (full)

Implement a function full() to check if the circular buffer is full or not. If the back after circular incrementation is equal to the front, then the buffer is empty.

Implementation

The below program demonstrates how we can implement a circular buffer using a std::vector in C++.

C++
#include <bits/stdc++.h>
using namespace std;

// Circular buffer class
class CircularBuffer {
private:
    vector<int> buffer;
    int front;
    int back;
    int capacity;

public:

    // Constructor to intialize circular buffer's data
    // members
    CircularBuffer(int _capacity) {
        
        // If the capacity is invalid
        if (_capacity < 0) {
            throw invalid_argument("Invalid capacity");
        }
        this->capacity = _capacity + 1;
        this->front = 0;
        this->back = 0;
        buffer.resize(capacity);
    }

    // Function to add an element to the buffer
    void push_back(int val) {
        if (full()) {
            throw overflow_error("CircularBuffer is full");
        }
        buffer[back] = val;
        back = (back + 1) % capacity;
    }

    // Function to remove an element from the buffer
    void pop_front() {
        if (empty()) {
            throw underflow_error("CircularBuffer is empty");
        }
        front = (front + 1) % capacity;
    }
    
    int getFront() {
        if (empty()) {
            throw out_of_range("CircularBuffer is empty");
        }
        return buffer[front];
    }
    
    int getBack() {
        if (empty()) {
            throw out_of_range("CircularBuffer is empty");
        }
        return (back == 0) ? buffer[capacity - 1] : buffer[back - 1];
    }

    // Function to check if the buffer is empty
    bool empty() const { return front == back; }

    // Function to check if the buffer is full
    bool full() const {
        return (back + 1) % capacity == front;
    }

    // Function to get the size of the buffer
    int size() const {
        if (back >= front) {
            return back - front;
        }
        return capacity - (front - back);
    }

    // Function to print the elements of the buffer
    void printBuffer() const {
        int idx = front;
        while (idx != back) {
            cout << buffer[idx] << " ";
            idx = (idx + 1) % capacity;
        }
        cout << endl;
    }
};

int main() {

    // Create a buffer of size 5
    CircularBuffer buffer(5);

    // Add elements to the buffer
    for (int i = 1; i <= 5; ++i) {
        buffer.push_back(i);
        cout << "Added: " << i << endl;
    }

    // Print elements of the buffer after adding elements
    cout << "Elements of the buffer: ";
    buffer.printBuffer();

    // Check the size of the circular buffer before deletion
    // of elements
    cout << "Buffer size: " << buffer.size() << endl;

    // Remove elements from the buffer
    for (int i = 0; i < 2; ++i) {
        cout << "Removed: " << buffer.getFront() << endl;
        buffer.pop_front();
    }
    // Print elements of the buffer after removing elements
    cout << "Elements of the buffer: ";
    buffer.printBuffer();

    // Check the size of the circular buffer after deletion
    // of elements
    cout << "Buffer size: " << buffer.size() << endl;
    cout << "Current Back: " << buffer.getBack() << endl;
    cout << "Current Front: " << buffer.getFront();
    return 0;
}

Output
Added: 1
Added: 2
Added: 3
Added: 4
Added: 5
Elements of the buffer: 1 2 3 4 5 
Buffer size: 5
Removed: 1
Removed: 2
Elements of the buffer: 3 4 5 
Buffer size: 3
Current Back: 5
Current Front: 3

Time Complexity: O(N), here N is the number of elements in the circular buffer
Auxiliary Space: O(N)


Next Article
Practice Tags :

Similar Reads