patterncppModerate
Circular Buffer C++11 Implementation
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()
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.
The main reason is that
Move
The move operators should usually be marked as
Swap
I normally implement the function
Swap is one of those rare places that you should use
The reason for this is if you change the types of your members (possibly to some custom type) then the
Design
Not really a circular buffer as there is no back or front concept implemented here.
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
noexceptCircularBuffer(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.