|
Boost Users : |
Subject: Re: [Boost-users] [Boost.CircularBuffer] begin()/end() arithmetic not working out quite right
From: David Baird (dhbaird_at_[hidden])
Date: 2009-07-27 15:18:53
Awesome! Thanks for the link to the specs. Unfortunately, looks like
circular_buffer is not the way to go for me :-(
I guess the picture is okay. I just got caught completely off guard. I
thought I knew what I was doing when I jumped in (i.e. thinking the
iterators would resemble std::vector), but then it turned out that my
assumptions were wrong. This is just a thought, but I think there
could be benefit for an alternative version of circular_buffer which
supports iterators like std::vector.
Thanks for the info,
-David
On Mon, Jul 27, 2009 at 1:32 AM, Jan Gaspar<jano_gaspar_at_[hidden]> wrote:
> Hi David,
>
> here is the link to the containers library as defined by standard:
>
> http://www.csci.csusb.edu/dick/c++std/cd2/lib-containers.html
>
> The picture in the documentation is just descriptive (how else would you draw a circular buffer). It doesn't say anything about its internal implementation.
>
> I'm afraid the way you want to use a circular buffer, this implementation is not applicable.
>
> But have a look at the Bounded Buffer example
>
> http://www.boost.org/doc/libs/1_39_0/libs/circular_buffer/doc/circular_buffer.html#examples
>
> This is the right way how to use circular_buffer in procuder/consumer scenario.
>
> Regards,
>
> Jan
>
>
>
>
>
> ----- Original Message ----
> From: David Baird <dhbaird_at_[hidden]>
> To: Jan Gaspar <jano_gaspar_at_[hidden]>
> Cc: boost-users_at_[hidden]
> Sent: Saturday, 25 July, 2009 22:25:46
> Subject: Re: [Boost.CircularBuffer] begin()/end() arithmetic not working out quite right
>
> Hmmm, well, I think I understand what you are saying. But it seems
> counter-intuitive to me that end() will always remain constant and
> that begin() will always move back. Even this graphic here seems to
> indicate that end() moves:
>
> http://www.boost.org/doc/libs/1_39_0/libs/circular_buffer/doc/circular_buffer.png
> (from http://www.boost.org/doc/libs/1_39_0/libs/circular_buffer/doc/circular_buffer.html)
>
> Unfortunately, that makes it hard to use circular_buffer in some of
> our applications. But I might be mistaken...
>
> It seems that circular_buffer works great for this scenario:
>
> for(i = buf.begin(); i= buf.end(); ++i) { ... }
>
> But my application is a little bit different from that. Essentially,
> we have a serial data stream that is being observed by several
> processes. There is one producer and many consumers. Each consumer
> has its own iterator. Our code is akin to this:
>
> // Make SIZE sufficiently large to obviate overflows:
> const int SIZE = 1024;
> char buf[SIZE];
> int tail = 0;
> int i1 = 0;
> int i2 = 0;
>
> // Producer process:
> while (true) { buf[tail++ % SIZE] = c; ... }
>
> // Consumer process 1:
> while (true) {
> while (tail != i1) { c = buf[i1++ % SIZE]; ... }
> }
>
> // Consumer process 2:
> while (true) {
> while (tail != i2) { c = buf[i2++ % SIZE]; ... }
> }
>
> At first glance, this seemed like a perfect application for
> Boost::circular_buffer. But when I delved in further, I just couldn't
> get the iterators to work out right in circular_buffer. I thought
> that something like this would be appropriate, but yet this does not
> work:
>
> const int SIZE = 1024;
> typedef circular_buffer<char> buf_type;
> buf_type buf(size);
>
> buf_type::iterator i1 = buf.begin();
> buf_type::iterator i2 = buf.begin();
>
> // Producer process:
> while (true) { buf.push_back(c); ... }
>
> // Consumer process 1:
> while (true) {
> // i1 will always equal buf.end(), despite .push_back() being called
> // ...thus, this fails:
> while (buf.end() != i1) { c = *i1++; ... }
> }
>
> // Consumer process 2:
> while (true) {
> while (buf.end() != i2) { c = *i2++; ... }
> }
>
> Do you think I am exceeding the intended application scope for
> circular_buffer here?
>
> I don't know where to find the specifications for the semantics of
> begin()/end(). Can you direct me towards a link? i've tried
> searching for things like "C++ container concepts" but that didn't
> yield any precise details about how begin()/end() should be affected
> by operations like push_back(). If I had to make a wild guess, I
> would guess that it actually isn't specified somewhere :-/
>
> Thanks,
> David
>
> On Wed, Jul 22, 2009 at 3:31 PM, Jan Gaspar<jano_gaspar_at_[hidden]> wrote:
>> Ah ... one more thing ... I made a mistake in my previous reply.
>>
>>> you just cannot rely on this. I don't think standard says anything about begin() moving forward after push_back(). Correct me if I'm wrong.
>>
>> should be read as
>>
>> "you just cannot rely on this. I don't think standard says anything about end() moving forward after push_back(). Correct me if I'm wrong."
>>
>> Sorry about the confusion.
>>
>> Jan
>>
>>
>>
>> ----- Original Message ----
>> From: David Baird <dhbaird_at_[hidden]>
>> To: Jan Gaspar <jano_gaspar_at_[hidden]>
>> Cc: boost-users_at_[hidden]
>> Sent: Wednesday, 22 July, 2009 22:30:13
>> Subject: Re: [Boost.CircularBuffer] begin()/end() arithmetic not working out quite right
>>
>> Hi Jan,
>>
>> Thanks for your reply and sorry for taking so long to respond.
>>
>> I am a bit confused by your response. I never did expect begin() to
>> move forward after push_back(). In my original post, what I said is
>> that I expect begin() will remain constant and that **end() will move
>> forward** each time push_back() is called.
>>
>> My main question is this: why does end() remain constant when
>> push_back() is called on a circular_buffer? In other words, why does
>> this assertion fail?:
>>
>> circular_buffer<int> buf(8);
>> circular_buffer<int>::iterator a;
>> circular_buffer<int>::iterator b;
>> a = buf.end();
>> buf.push_back(1);
>> b = buf.end();
>> assert(a != b); // fails
>>
>> If I use an STL vector instead of circular_buffer, I get exactly the
>> results I expect (as along as I call .reserve() on it prior, so that
>> iterators are not invalidated by a realloc).
>>
>> -David
>>
>> On Thu, Jun 11, 2009 at 1:58 AM, Jan Gaspar<jano_gaspar_at_[hidden]> wrote:
>>>
>>> Hi David,
>>>
>>> you just cannot rely on this. I don't think standard says anything about begin() moving forward after push_back(). Correct me if I'm wrong.
>>>
>>> The way how it is implemented is that if the circular_buffer is empty begin() returns the same iterator as end().
>>>
>>> There is also a note about iterator invalidation for push_back():
>>> "Does not invalidate any iterators with the exception of iterators pointing to the overwritten element."
>>>
>>> It means iterator 'a' in your first example will point to the same element as it was before calling push_back() - which is end(). This explains the behaviour you are describing.
>>>
>>> Regards,
>>>
>>> Jan
>>>
>>>
>>>
>>>
>>> ----- Original Message ----
>>> From: David Baird <dhbaird_at_[hidden]>
>>> To: Jan Gaspar <jano_gaspar_at_[hidden]>; boost-users_at_[hidden]
>>> Sent: Thursday, 11 June, 2009 1:01:54
>>> Subject: [Boost.CircularBuffer] begin()/end() arithmetic not working out quite right
>>>
>>> Hi,
>>>
>>> Firstly, thanks for the work on a circular buffer. This is very
>>> useful since many of my applications require it. I am having a
>>> problem though...
>>>
>>> I am using Boost 1.38.0. When I call push_back(), the iterator math
>>> makes it appear that begin() moves backwards and end() remains
>>> constant. (Based on other STL libraries, I expect that begin() will
>>> remain constant and end() will keep advancing as I call push_back()).
>>>
>>> In other words, this assertion fails (but I expect it to succeed):
>>>
>>> circular_buffer<int> buf(8);
>>> circular_buffer<int>::iterator a;
>>> circular_buffer<int>::iterator b;
>>> a = buf.begin();
>>> buf.push_back(1);
>>> b = buf.begin();
>>> assert(a == b); // Fails!!
>>>
>>> Also, this code fails too (but I expect it to succeed):
>>>
>>> circular_buffer<int> buf(8);
>>> circular_buffer<int>::iterator a;
>>> circular_buffer<int>::iterator b;
>>> a = buf.end();
>>> buf.push_back(1);
>>> b = buf.end();
>>> assert(a != b); // Also fails!
>>>
>>> Below is a full example that you can compile and try out:
>>>
>>> #include <boost/circular_buffer.hpp>
>>> #include <stdio.h>
>>>
>>> int
>>> main ()
>>> {
>>> typedef boost::circular_buffer<int> buf_type;
>>> // Instead of "end" moving ahead, "begin" is moving backwards when //
>>> // using "push_back".
>>> {
>>> buf_type buf1(1024);
>>> buf_type::iterator a;
>>> buf_type::iterator b;
>>> a = buf1.end();
>>> buf1.push_back(1);
>>> buf1.push_back(2);
>>> b = buf1.end();
>>> printf ("%d\n", a == b);
>>> // >>>
>>> // got: 1
>>> // expected: 0
>>> printf ("%d, %d\n", a-buf1.begin(), b-buf1.begin());
>>> // >>>
>>> // got: 2, 2
>>> // expected: 0, 2
>>> }
>>> {
>>> buf_type buf2(1024);
>>> buf_type::iterator c;
>>> buf_type::iterator d;
>>> c = buf2.begin();
>>> buf2.push_back(1);
>>> buf2.push_back(2);
>>> d = buf2.begin();
>>> printf ("%d\n", c == d);
>>> // >>>
>>> // got: 0
>>> // expected: 1
>>> // (i.e. "begin()" is not still pointing to first item!!
>>> // This is incorrect, isn't it?)
>>> printf ("%d, %d\n", buf2.end()-c, buf2.end()-d);
>>> // >>>
>>> // got: 0, 2
>>> // expected: 2, 2
>>> }
>>> return 0;
>>> }
>>>
>>>
>>> Thanks,
>>> David
>>>
>>>
>>>
>>>
>>>
>>
>>
>>
>>
>>
>
>
>
>
>
Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net