HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppModerate

Circular Buffer C++11 Implementation

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
implementationcircularbuffer

Problem

Here's the implementation of a common data structure I use at work, mainly for logging purposes.

I tried to make it C++11-compliant, but even if this standard has been around for a few years, it is still quite new to me since I play with it only in my spare time (locked on VS2010 at work, which has a poor implementation of then-so-called C++0X.)

So, feel free to criticize and, hopefully, suggest some improvement; I'm especially interested in exception safety and correct implementation of move semantics (other than code style, performance issues and so on...)

I know it is still a naive implementation, so I intentionally avoided allocators and iterators by now, but...dont't be shy if you have something in mind.

```
#ifndef CIRCULAR_BUFFER_H
#define CIRCULAR_BUFFER_H

#include
#include
#include
#include
#include

template
class CircularBuffer
{
public:
typedef size_t size_type;
typedef T& reference;
typedef const T& const_reference;
typedef T* pointer;
typedef const T* const_pointer;

explicit CircularBuffer(size_type capacity);
CircularBuffer(const CircularBuffer &rhs);
CircularBuffer(CircularBuffer&& rhs);
~CircularBuffer() { if (_buffer) delete[] _buffer; }

CircularBuffer& operator=(CircularBuffer rhs);

size_type size() const { return (_full ? _capacity : _front); }
size_type capacity() const { return _capacity; }
bool is_full() const { return _full; }

const_reference operator[](size_type index) const;
reference operator[](size_type index);

void add(T item);
void resize(size_type new_capacity);

friend void swap(CircularBuffer &a, CircularBuffer &b)
{
std::swap(a._buffer, b._buffer);
std::swap(a._capacity, b._capacity);
std::swap(a._front, b._front);
std::swap(a._full, b._full);
}

private:
pointer _buffer;
size_type _capacity;
size_type _front;
bool _full;

CircularBuffer();
};

template
CircularBuffer::CircularBuffer()

Solution

Rather than implement all the memory management yourself use an existing container and just implement the circular part yourself.

template 
class CircularBuffer
{
    std::vector  buffer; // maybe there is a better one
    ...                     // I would think on this a bit.


The main reason is that std::vector will not construct the elements that are not used. Yours on the other hand default constructs all the elements in _buffer. If T is not default constructible this is a problem. If T is expensive to default construct this is a problem.

Move

The move operators should usually be marked as noexcept

CircularBuffer(CircularBuffer&& rhs) noexcept;
// Also you should probably have an explicit move assignment.
CircularBuffer& operator=(CircularBuffer&& rhs) noexcept;


Swap

I normally implement the function swap in terms of a member function swap that I mark as noexcept (because the move operators usually need swap and they need it to be noexcept).

friend void swap(CircularBuffer& lhs, CircularBuffer& rhs)
{
    lhs.swap(rhs);
}


Swap is one of those rare places that you should use using std::swap.

void swap(CircularBuffer& rhs)
{
    using std::swap;
    swap(_buffer,   rhs._buffer);
    swap(_capacity, rhs._capacity);
    swap(_front,    rhs._front);
    swap(_full,     rhs._full);
}


The reason for this is if you change the types of your members (possibly to some custom type) then the swap() function continues to work without modification.

Design

Not really a circular buffer as there is no back or front concept implemented here.

Code Snippets

template <typename T>
class CircularBuffer
{
    std::vector<T>  buffer; // maybe there is a better one
    ...                     // I would think on this a bit.
CircularBuffer(CircularBuffer<T>&& rhs) noexcept;
// Also you should probably have an explicit move assignment.
CircularBuffer<T>& operator=(CircularBuffer<T>&& rhs) noexcept;
friend void swap(CircularBuffer<T>& lhs, CircularBuffer<T>& rhs)
{
    lhs.swap(rhs);
}
void swap(CircularBuffer<T>& rhs)
{
    using std::swap;
    swap(_buffer,   rhs._buffer);
    swap(_capacity, rhs._capacity);
    swap(_front,    rhs._front);
    swap(_full,     rhs._full);
}

Context

StackExchange Code Review Q#134911, answer score: 11

Revisions (0)

No revisions yet.