On 8/10/24 16:03, Andrzej Krzemienski via Boost wrote:
Hi Everyone, This is a couple of questions about Boost.Circular_buffer, but also about Boost in general.
A colleague of mine says he needs a ring buffer for usage in the embedded context, and I am investigating why he chooses to write his own rather than using Boost.Circular_Buffer, even though he knows the latter exists.
It is a natural expectation for containers like static_vector/inplace_vector, array, circular_buffer to be a natural fit for the embedded contexts, as, at least in principle, they should not require any memory allocation.
Not necessarily. These types are useful beyond embedded environments, where exceptions and dynamic memory allocations are allowed and actively used.
Question 1: Is Boost a suitable place for libraries targeting systems where exceptions, RTTI and memory allocation are banned?
I think, if a library provides an option to be usable in such environments, it is definitely welcome. If the library targets such environments *exclusively* then its usefulness in other, more widespread and less restricted domains would be rather limited.
Question 2: Is it a reasonable expectation of a ring buffer to not require allocations?
There doesn't need to be a single type of a ring buffer. Similarly to vector/static_vector/small_vector, there can be multiple ring buffer types that make different tradeoffs wrt. their storage and other properties. Specifically re. Boost.CircularBuffer, I see no problem that it performs dynamic memory allocations given its support for dynamic sizes and capacities. That is, circular_buffer provides a ring buffer with (reasonably) unlimited capacity, and it is good at that purpose. There may be other use cases, where a different set of tradeoffs are more suitable. For example, I've written a ring buffer adapter that operates on an array of fixed capacity (meaning that all elements of the array are constructed upon the ring buffer construction rather than on insertion), which was better suited for a given use case than Boost.CircularBuffer. Again, there's nothing wrong in having different ring buffer types that make different tradeoffs and fit different use cases. If your colleague's use case is sufficiently different from that of Boost.CircularBuffer, there's nothing wrong with implementing his own version. If such a use case is widespread enough, it would make sense to extract (or reimplement) that version as a Boost library, so that it is useful to many.
Question 4: Maybe there would be a value, at least for some Boost libraries, to provide a single-header, header-only variant that works under some assumptions, like C++11 compiler?
If this means duplicating code and potential ODR issues, I would be opposed.
My colleagues use case is that, because removals from the buffer can occur asynchronously, when doing a pop_back() there is no way to be sure that the buffer is non-empty, so this would require a function that does the check and the pop_back at one go.
I'm not sure how this relates to the previous questions, but why the need for a function that does two things at once? Why not `if (!cb.empty()) cb.pop_back();`?