From 39f497ee192e2ea338eaf4563a8a4b7ea7fbaf7c Mon Sep 17 00:00:00 2001
From: Jan Gaspar The The A brief example using the
+
-
- Templated Circular Buffer Container
- circular_buffer<T, Alloc>
-
- 
Templated Circular Buffer Container
+ circular_buffer<T, Alloc>
+
+
+

Contents
- Description
- Simple Example
- Synopsis
- Rationale
- Header files
- Modeled concepts
- Template Parameters
- Public Types
- Constructors & Destructor
- Public Member Functions
- Standalone Functions
- Semantics
- Caveats
- Debug Support
- Example
- Notes
- See also
- Ideas for Future Improvements
- Acknowledgments
+ Description
+ Simple Example
+ Synopsis
+ Rationale
+ Header files
+ Modeled concepts
+ Template Parameters
+ Public Types
+ Constructors & Destructor
+ Public Member Functions
+ Standalone Functions
+ Semantics
+ Caveats
+ Debug Support
+ Example
+ Notes
+ See also
+ Ideas for Future Improvements
+ Acknowledgments
+
- 
+
-
-
+
+
Figure:
- The circular buffer (for someone known as ring or cyclic buffer).
- The circular buffer (for someone known as ring or cyclic buffer).
+
Description
- circular_buffer container provides fixed capacity storage with
- constant time insertion and removal of elements at each end of a circular
- buffer. When the capacity of the circular_buffer is exhausted,
- inserted elements will cause elements at the opposite end to be overwritten (see the Figure).
- The circular_buffer only allocates memory when
- created, when the capacity is adjusted explicitly, or as necessary to
- accommodate a resizing or assign operation. (There is also a circular_buffer_space_optimized
- available. It is an adaptor of the circular_buffer
- which does not allocate memory at once when created rather it allocates memory as needed.)
- circular_buffer container provides fixed capacity storage with
+ constant time insertion and removal of elements at each end of a circular
+ buffer. When the capacity of the circular_buffer is exhausted,
+ inserted elements will cause elements at the opposite end to be overwritten (see the Figure).
+ The circular_buffer only allocates memory when
+ created, when the capacity is adjusted explicitly, or as necessary to
+ accommodate a resizing or assign operation. (There is also a circular_buffer_space_optimized
+ available. It is an adaptor of the circular_buffer
+ which does not allocate memory at once when created rather it allocates memory as needed.)
+
Simple Example
circular_buffer:
-
#include <boost/circular_buffer.hpp>
int main(int argc, char* argv[]) {
@@ -79,7 +79,7 @@
// The buffer is full now, pushing subsequent
// elements will overwrite the front-most elements.
-
+
cb.push_back(4); // Overwrite 1 with 4.
cb.push_back(5); // Overwrite 2 with 5.
@@ -125,11 +125,11 @@ public:
typedef typename Alloc::value_type value_type;
template <class InputIterator>
- circular_buffer(size_type capacity,
- InputIterator first, InputIterator last,
+ circular_buffer(size_type capacity,
+ InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
circular_buffer(const circular_buffer<T,Alloc>& cb);
- circular_buffer(size_type capacity,
+ circular_buffer(size_type capacity,
value_type item, const allocator_type& alloc = allocator_type());
explicit circular_buffer(size_type capacity, const allocator_type& alloc = allocator_type());
~circular_buffer();
@@ -210,84 +210,84 @@ template <class T, class Alloc>
Rationale
- A contiguous region of memory utilized as a circular buffer has several unique
- and useful characteristics:
-
+ A contiguous region of memory utilized as a circular buffer has several unique
+ and useful characteristics:
+
-
- Fixed memory use and no implicit or unexpected memory
- allocation.
-
+ Fixed memory use and no implicit or unexpected memory
+ allocation.
+
-
- Fast constant-time insertion and removal of elements
- from the front and back.
-
+ Fast constant-time insertion and removal of elements
+ from the front and back.
+
-
- Fast constant-time random access of elements.
-
+ Fast constant-time random access of elements.
+
-
- Suitability for real-time and performance critical applications.
-
-
+ Suitability for real-time and performance critical applications.
+
+
The circular_buffer container provides a similar interface to std::vector,
- std::deque and std::list including push,
- pop, insert, erase, iterators and
- compatibility with std algorithms.
-
+ std::deque and std::list including push,
+ pop, insert, erase, iterators and
+ compatibility with std algorithms.
+
Possible applications of the circular_buffer include:
-
+
The design of the circular_buffer container is guided by the
- following principles:
-
The design of the circular_buffer container is guided by the
+ following principles:
+
std containers and algorithms.
+ Interoperable with other std containers and algorithms.
circular_buffer_space_optimized
- is such an example of the adaptor.)
+ Suitable for specialization by means of adaptors. (The circular_buffer_space_optimized
+ is such an example of the adaptor.)
- The circular_buffer is defined in the file
+ The circular_buffer is defined in the file
boost/circular_buffer.hpp.
There is also a forward declaration for the circular_buffer in the header file
boost/circular_buffer_fwd.hpp.
-
Random Access - Container, - Front Insertion Sequence, - Back Insertion Sequence, - Assignable (SGI specific), - Equality Comparable, - LessThan Comparable (SGI specific) -
+Random Access + Container, + Front Insertion Sequence, + Back Insertion Sequence, + Assignable (SGI specific), + Equality Comparable, + LessThan Comparable (SGI specific) +
template <class InputIterator>
- circular_buffer(size_type capacity,
+ circular_buffer(size_type capacity,
InputIterator first, InputIterator last,
const allocator_type& alloc = allocator_type());
(*this).size()
+(*this).size()
== capacity && (*this)[0] == (*this)[1] == ... == (*this).back() == item
- template <class InputIterator>
+ template <class InputIterator>
void assign(InputIterator first, InputIterator last);
| Return pointer to data stored in the circular buffer as a continuous array of values. |
This method can be useful e.g. when passing the stored data into the legacy C API.
+
template <class InputIterator>
@@ -1559,7 +1559,7 @@ Change the size of the circular buffer. |
template <class InputIterator>
- void rinsert(iterator pos,
+ void rinsert(iterator pos,
InputIterator first, InputIterator last);
- template <class T, class Alloc>
+ template <class T, class Alloc>
bool operator!=(const circular_buffer<T,Alloc>& lhs, const circular_buffer<T,Alloc>& rhs);
- template <class T, class Alloc>
+ template <class T, class Alloc>
bool operator<(const circular_buffer<T,Alloc>& lhs, const circular_buffer<T,Alloc>& rhs);
- template <class T, class Alloc>
+ template <class T, class Alloc>
bool operator<=(const circular_buffer<T,Alloc>& lhs, const circular_buffer<T,Alloc>& rhs);
- template <class T, class Alloc>
+ template <class T, class Alloc>
bool operator==(const circular_buffer<T,Alloc>& lhs, const circular_buffer<T,Alloc>& rhs);
- template <class T, class Alloc>
+ template <class T, class Alloc>
bool operator>(const circular_buffer<T,Alloc>& lhs, const circular_buffer<T,Alloc>& rhs);
- template <class T, class Alloc>
+ template <class T, class Alloc>
bool operator>=(const circular_buffer<T,Alloc>& lhs, const circular_buffer<T,Alloc>& rhs);
- template <class T, class Alloc>
+ template <class T, class Alloc>
void swap(circular_buffer<T,Alloc>& lhs, circular_buffer<T,Alloc>& rhs);
The behaviour of insertion for circular_buffer is as follows:
-
circular_buffer remains fixed unless adjusted
- via set_capacity or resize.
-
+ The capacity of a circular_buffer remains fixed unless adjusted
+ via set_capacity or resize.
+
insert will
- overwrite front elements as necessary.
-
+ insert will
+ overwrite front elements as necessary.
+
rinsert will overwrite back elements as necessary.
- rinsert will overwrite back elements as necessary.
+
+
The behaviour of resizing a circular_buffer is as follows:
-
resize. (The
- capacity can be only increased, not decreased.)
- resize. (The
+ capacity can be only increased, not decreased.)
+
+
The behaviour of assigning to a circular_buffer is as follows:
-
assign. (The
- capacity can be only increased, not decreased.)
- The rules for iterator (and result of data())
- invalidation for circular_buffer are as follows:
-
assign. (The
+ capacity can be only increased, not decreased.)
+
+
+ The rules for iterator (and result of data())
+ invalidation for circular_buffer are as follows:
+
insert at the end of the circular_buffer (including
- push_back) does not invalidate any iterator except
- the case the iterator points to the overwritten element.
-
+ insert at the end of the circular_buffer (including
+ push_back) does not invalidate any iterator except
+ the case the iterator points to the overwritten element.
+
rinsert at the beginning of the circular_buffer (including
- push_front) does not invalidate any iterator
- except the case the iterator points to the overwritten element.
-
+ rinsert at the beginning of the circular_buffer (including
+ push_front) does not invalidate any iterator
+ except the case the iterator points to the overwritten element.
+
insert in the middle of the circular_buffer invalidates
- iterators pointing to the elements at the insertion point and behind the
- insertion point. It also invalidates iterators pointing to the overwritten
- element(s).
-
+ insert in the middle of the circular_buffer invalidates
+ iterators pointing to the elements at the insertion point and behind the
+ insertion point. It also invalidates iterators pointing to the overwritten
+ element(s).
+
rinsert in the middle of the circular_buffer invalidates
- iterators pointing to the elements before the insertion point and iterators
- pointing to the overwritten element(s).
-
+ rinsert in the middle of the circular_buffer invalidates
+ iterators pointing to the elements before the insertion point and iterators
+ pointing to the overwritten element(s).
+
erase at the end of the circular_buffer (including pop_back) invalidates only iterators pointing to
- the erased element(s).
-
+ erase at the end of the circular_buffer (including pop_back) invalidates only iterators pointing to
+ the erased element(s).
+
pop_front
- invalidates only iterators pointing to the erased element.
-
+ pop_front
+ invalidates only iterators pointing to the erased element.
+
erase at the beginning or in the middle of the circular_buffer invalidates iterators pointing to
- the erased element(s) and iterators pointing to the elements behind the erase
- point.
-
+ erase at the beginning or in the middle of the circular_buffer invalidates iterators pointing to
+ the erased element(s) and iterators pointing to the elements behind the erase
+ point.
+
data, set_capacity, resize, operator=,
- assign, swap and clear invalidate all
- iterators pointing to the circular_buffer.
- In addition to the preceding rules the iterators get also invalidated due to
- overwritting (e.g. iterator pointing to the front-most element gets invalidated
- when inserting into the full circular_buffer). They get
- invalidated in that sense they do not point to the same element as before but
- they do still point to the same valid place in the memory. If you want
- to rely on this feature you have to turn of the Debug Support
- otherwise an assertion will report an error if such invalidated iterator is used.
data, set_capacity, resize, operator=,
+ assign, swap and clear invalidate all
+ iterators pointing to the circular_buffer.
+
+
+ In addition to the preceding rules the iterators get also invalidated due to
+ overwritting (e.g. iterator pointing to the front-most element gets invalidated
+ when inserting into the full circular_buffer). They get
+ invalidated in that sense they do not point to the same element as before but
+ they do still point to the same valid place in the memory. If you want
+ to rely on this feature you have to turn of the Debug Support
+ otherwise an assertion will report an error if such invalidated iterator is used.
The circular_buffer should not be used for storing pointers to
- dynamically allocated objects. When a circular_buffer becomes
- full, further insertion will overwrite the stored pointers - resulting in a memory
- leak. One recommend alternative is the use of smart pointers [1].
- (Any container of std::auto_ptr is considered particularly
- hazardous. [2])
-
Elements inserted near the front of a full circular_buffer can be
- lost. According to the semantics of insert,
- insertion overwrites front-most items as necessary - possibly including
- elements currently being inserted at the front of the buffer.
- Conversely, push_front to a full circular_buffer is
- guaranteed to overwrite the back-most element.
-
Elements inserted near the back of a full circular_buffer can be
- lost. According to the semantics of rinsert,
- insertion overwrites front-most items as necessary - possibly including
- elements currently being inserted at the back of the buffer. Conversely,
- push_back to a full circular_buffer is guaranteed to
- overwrite the front-most element.
-
While internals of a circular_buffer are circular, iterators are not.
- Iterators of a circular_buffer are only valid for the range [begin(),
- end()]. E.g. iterators (begin() - 1) and (end() + 1)
- are invalid.
-
The circular_buffer should not be used for storing pointers to
+ dynamically allocated objects. When a circular_buffer becomes
+ full, further insertion will overwrite the stored pointers - resulting in a memory
+ leak. One recommend alternative is the use of smart pointers [1].
+ (Any container of std::auto_ptr is considered particularly
+ hazardous. [2])
+
Elements inserted near the front of a full circular_buffer can be
+ lost. According to the semantics of insert,
+ insertion overwrites front-most items as necessary - possibly including
+ elements currently being inserted at the front of the buffer.
+ Conversely, push_front to a full circular_buffer is
+ guaranteed to overwrite the back-most element.
+
Elements inserted near the back of a full circular_buffer can be
+ lost. According to the semantics of rinsert,
+ insertion overwrites front-most items as necessary - possibly including
+ elements currently being inserted at the back of the buffer. Conversely,
+ push_back to a full circular_buffer is guaranteed to
+ overwrite the front-most element.
+
While internals of a circular_buffer are circular, iterators are not.
+ Iterators of a circular_buffer are only valid for the range [begin(),
+ end()]. E.g. iterators (begin() - 1) and (end() + 1)
+ are invalid.
+
In order to help a programmer to avoid and find common bugs, the circular_buffer
- contains a kind of debug support.
- The circular_buffer maintains a list of valid iterators. As soon
- as any element gets destroyed all iterators pointing to this element are
- removed from this list and explicitly invalidated (an invalidation flag is
- set). The debug support also consists of many assertions (BOOST_ASSERT
- macros) which ensure the circular_buffer and its iterators are
- used in the correct manner at runtime. In case an invalid iterator is used the
- assertion will report an error. The connection of explicit iterator
- invalidation and assertions makes a very robust debug technique which catches
- most of the errors.
Moreover, the uninitialized memory allocated by circular_buffer is
- filled with the value 0xcc in the debug mode. This can help the
- programmer when debugging the code to recognize the initialized memory from the
- uninitialized. For details refer the
- source code.
-
circular_buffer maintains a list of valid iterators. As soon
+ as any element gets destroyed all iterators pointing to this element are
+ removed from this list and explicitly invalidated (an invalidation flag is
+ set). The debug support also consists of many assertions (BOOST_ASSERT
+ macros) which ensure the circular_buffer and its iterators are
+ used in the correct manner at runtime. In case an invalid iterator is used the
+ assertion will report an error. The connection of explicit iterator
+ invalidation and assertions makes a very robust debug technique which catches
+ most of the errors.
+ Moreover, the uninitialized memory allocated by circular_buffer is
+ filled with the value 0xcc in the debug mode. This can help the
+ programmer when debugging the code to recognize the initialized memory from the
+ uninitialized. For details refer the
+ source code.
+
The debug support is enabled only in the debug mode (when the NDEBUG
- is not defined). It can also be explicitly disabled by defining BOOST_DISABLE_CB_DEBUG
- macro.
BOOST_DISABLE_CB_DEBUG
+ macro.
The following example includes various usage of the circular_buffer.
-
#include <boost/circular_buffer.hpp>
#include <numeric>
#include <assert.h>
@@ -2062,7 +2062,7 @@ Swap the contents of two circular buffers.
int main(int argc, char* argv[])
{
// create a circular buffer of capacity 3
- boost::circular_buffer<int> cb(3);
+ boost::circular_buffer<int> cb(3);
// insert some elements into the circular buffer
cb.push_back(1);
@@ -2090,35 +2090,35 @@ Swap the contents of two circular buffers.
assert(cb.full());
assert(cb.size() == 3);
assert(cb.capacity() == 3);
-
+
return 0;
}
- The circular_buffer has a capacity of three int.
- Therefore, the size of the buffer will not exceed three. The
- accumulate algorithm evaluates the sum of the stored
- elements. The semantics of the circular_buffer can be inferred from
- the assertions.
-
The circular_buffer has a capacity of three int.
+ Therefore, the size of the buffer will not exceed three. The
+ accumulate algorithm evaluates the sum of the stored
+ elements. The semantics of the circular_buffer can be inferred from
+ the assertions.
+
[1] A good implementation of smart pointers is included in - Boost. -
-[2] Never create a circular buffer of std::auto_ptr.
- Refer to Scott Meyers' excellent book Effective
- STL for a detailed discussion. (Meyers S., Effective STL: 50 Specific
- Ways to Improve Your Use of the Standard Template Library.
- Addison-Wesley, 2001.)
-
[2] Never create a circular buffer of std::auto_ptr.
+ Refer to Scott Meyers' excellent book Effective
+ STL for a detailed discussion. (Meyers S., Effective STL: 50 Specific
+ Ways to Improve Your Use of the Standard Template Library.
+ Addison-Wesley, 2001.)
+
boost::circular_buffer_space_optimized,
- std::vector,
- std::list, std::deque
-
The formal review revealed that the library is lack of adaptors which would provide additional @@ -2130,18 +2130,18 @@ e.g. for invoking some method on the element being overwritten or for throwing a exception.
The circular_buffer has a short history. Its first version was a std::deque adaptor. This container was not very
-effective because of many reallocations when inserting/removing an element.
-Thomas Wenish did a review of this version and motivated me to create a circular
+
The circular_buffer has a short history. Its first version was a std::deque adaptor. This container was not very
+effective because of many reallocations when inserting/removing an element.
+Thomas Wenish did a review of this version and motivated me to create a circular
buffer which allocates memory at once when created.
The second version adapted std::vector but it has been abandoned
- soon because of limited control over iterator invalidation.
The current version is - a full-fledged STL compliant container. Pavel Vozenilek did a thorough review of this version - and came with many good ideas and improvements. Also, I would like to - thank Howard Hinnant, Nigel Stewart and everyone who participated at the formal review for valuable - comments and ideas. -
+The second version adapted std::vector but it has been abandoned
+ soon because of limited control over iterator invalidation.
The current version is + a full-fledged STL compliant container. Pavel Vozenilek did a thorough review of this version + and came with many good ideas and improvements. Also, I would like to + thank Howard Hinnant, Nigel Stewart and everyone who participated at the formal review for valuable + comments and ideas. +
- circular_buffer_space_optimized<T, Alloc>- |
- ![]() |
- ![]() |
+
The circular_buffer_space_optimized container is an adaptor of the
- circular_buffer. The
- functionality of the circular_buffer_space_optimized is similar to
- the base circular_buffer except it does not allocate memory at
- once when created rather it allocates memory as needed. (The predictive memory
- allocation is similar to typical std::vector implementation.)
- Moreover the memory is automatically freed as the size of the container
- decreases.
-
circular_buffer_space_optimized is similar to
+ the base circular_buffer except it does not allocate memory at
+ once when created rather it allocates memory as needed. (The predictive memory
+ allocation is similar to typical std::vector implementation.)
+ Moreover the memory is automatically freed as the size of the container
+ decreases.
+
| - | ![]() |
- ![]() |
+
| Figure: | -The memory allocation process of the space optimized circular
- buffer. The min_capacity represents the minimal guaranteed amount
- of allocated memory. The allocated memory will never drop under this value. By
- default the min_capacity is set to 0.
- |
- The memory allocation process of the space optimized circular
+ buffer. The min_capacity represents the minimal guaranteed amount
+ of allocated memory. The allocated memory will never drop under this value. By
+ default the min_capacity is set to 0.
+ |
+
The auto-resizing mode of the space optimized circular buffer can be useful in
- situations when the container can possibly store large number of elements but
- most of its lifetime the container stores just few of them. The usage of the circular_buffer_space_optimized
- will result in decreased memory consumption and can improve the CPU cache
- effectiveness.
-
The auto-resizing mode of the space optimized circular buffer can be useful in
+ situations when the container can possibly store large number of elements but
+ most of its lifetime the container stores just few of them. The usage of the circular_buffer_space_optimized
+ will result in decreased memory consumption and can improve the CPU cache
+ effectiveness.
+
- The circular_buffer_space_optimized is defined in the file
+ The circular_buffer_space_optimized is defined in the file
boost/circular_buffer.hpp.
There is also a forward declaration for the circular_buffer_space_optimized in the header file
boost/circular_buffer_fwd.hpp.
-
Random Access - Container, - Front Insertion Sequence, - Back Insertion Sequence, - Assignable (SGI specific), - Equality Comparable, - LessThan Comparable (SGI specific) -
+Random Access + Container, + Front Insertion Sequence, + Back Insertion Sequence, + Assignable (SGI specific), + Equality Comparable, + LessThan Comparable (SGI specific) +
Template parameters, members and friend functions of the circular_buffer_space_optimized
- are almost the same as for the base circular_buffer. Refer the circular_buffer
- documentation and also its
- source code documentation for a detailed description.
-
The specific methods of the circular_buffer_space_optimized are
- listed below.
-
circular_buffer. Refer the circular_buffer
+ documentation and also its
+ source code documentation for a detailed description.
+
+ The specific methods of the circular_buffer_space_optimized are
+ listed below.
+
The behaviour of memory auto-resizing is as follows: -
+circular_buffer_space_optimized
- is created.
- circular_buffer_space_optimized
+ is created.
+
circular_buffer_space_optimized
- container is created the allocated memory reflects the size of the container.
- circular_buffer_space_optimized
+ container is created the allocated memory reflects the size of the container.
+
push_back, push_front, insert and rinsert
- will predictively increase the allocated memory if necessary. (The predictive
- memory allocation is similar to std::vector.)
- push_back, push_front, insert and rinsert
+ will predictively increase the allocated memory if necessary. (The predictive
+ memory allocation is similar to std::vector.)
+
set_capacity, resize, assign, insert
- (range or n items), rinsert (range or n items), erase
- (range) and clear
- will accommodate the allocated memory as necessary.
- set_capacity, resize, assign, insert
+ (range or n items), rinsert (range or n items), erase
+ (range) and clear
+ will accommodate the allocated memory as necessary.
+
pop_back, pop_front, erase and clear
- will predictively decrease the allocated memory.
- The semantics of the circular_buffer_space_optimized then follows
- the semantics of the base circular_buffer
- except the invalidation rules.
-
pop_back, pop_front, erase and clear
+ will predictively decrease the allocated memory.
+
+
+ The semantics of the circular_buffer_space_optimized then follows
+ the semantics of the base circular_buffer
+ except the invalidation rules.
+
The rule for iterator invalidation for circular_buffer_space_optimized
- is as follows:
-
data, set_capacity, resize, operator=,
- assign, swap, push_back, push_front,
- pop_back, pop_front, insert, rinsert,
- erase and clear invalidate all iterators pointing to
- the circular_buffer_space_optimized.
- data, set_capacity, resize, operator=,
+ assign, swap, push_back, push_front,
+ pop_back, pop_front, insert, rinsert,
+ erase and clear invalidate all iterators pointing to
+ the circular_buffer_space_optimized.
+
+
boost::circular_buffer,
- std::vector
-
The idea of the space optimized circular buffer has been introduced by Pavel - Vozenilek. -
+The idea of the space optimized circular buffer has been introduced by Pavel + Vozenilek. +