C++ 迭代器,调用end()的结果的值会随着数据添加到循环缓冲区而改变
今天早些时候我发现,C++ 迭代器,调用end()的结果的值会随着数据添加到循环缓冲区而改变,c++,boost,iterator,std,circular-buffer,C++,Boost,Iterator,Std,Circular Buffer,今天早些时候我发现,boost::circular缓冲区的迭代器在多线程环境中的行为与我预期的不一样。(虽然公平地说,它们的行为也不同于我在单线程程序中所想的) 如果调用buffer.begin()和buffer.end()来表示用于循环特定数据序列的迭代器。如果将更多数据添加到循环\u缓冲区,则结束迭代器的值将更改。显然,如果在数据更改后再次调用end(),您会期望得到不同的结果。但令人困惑的是您已经更改的迭代器对象的值 是否有一种方法可以创建迭代器,使您能够处理循环缓冲区中的一组数据,并且即
boost::circular
缓冲区的迭代器在多线程环境中的行为与我预期的不一样。(虽然公平地说,它们的行为也不同于我在单线程程序中所想的)
如果调用buffer.begin()
和buffer.end()
来表示用于循环特定数据序列的迭代器。如果将更多数据添加到循环\u缓冲区
,则结束迭代器的值将更改。显然,如果在数据更改后再次调用end()
,您会期望得到不同的结果。但令人困惑的是您已经更改的迭代器对象的值
是否有一种方法可以创建迭代器,使您能够处理循环缓冲区中的一组数据,并且即使在处理一组数据时向缓冲区添加了其他数据,迭代器的值也不会更改
如果没有,是否有一个首选的“非迭代器”模式可以应用,或者有一个不同的容器类可以允许这样做
#include "stdafx.h"
#include <boost\thread.hpp>
#include <boost\thread\thread_time.hpp>
#include <boost\circular_buffer.hpp>
int _tmain(int argc, _TCHAR* argv[])
{
boost::circular_buffer<int> buffer(20);
buffer.push_back(99);
buffer.push_back(99);
buffer.push_back(99);
boost::circular_buffer<int>::const_iterator itBegin = buffer.begin();
boost::circular_buffer<int>::const_iterator itEnd = buffer.end();
int count = itEnd - itBegin;
printf("itEnd - itBegin == %i\n", count); //prints 3
/* another thread (or this one) pushes an item*/
buffer.push_back(99);
/*we check values of begin and end again, they've changed, even though we have not done anything in this thread*/
count = itEnd - itBegin;
printf("itEnd - itBegin == %i\n", count); //prints 4
}
#包括“stdafx.h”
#包括
#包括
#包括
int _tmain(int argc,_TCHAR*argv[]
{
boost::循环缓冲区(20);
缓冲器。推回(99);
缓冲器。推回(99);
缓冲器。推回(99);
boost::circular\u buffer::const\u迭代器itBegin=buffer.begin();
boost::circular\u buffer::const\u迭代器itEnd=buffer.end();
int count=itEnd-itBegin;
printf(“itEnd-itBegin=%i\n”,count);//打印3
/*另一个线程(或此线程)推送一个项目*/
缓冲器。推回(99);
/*我们再次检查begin和end的值,它们已经更改,即使我们在这个线程中没有做任何事情*/
计数=itEnd-itBegin;
printf(“itEnd-itBegin=%i\n”,count);//打印4
}
更新以获取对ronag的更详细响应 我正在寻找生产者-消费者类型的模型,boost文档中显示的有界缓冲区示例与我需要的非常接近。除了以下两个例外
文档明确声明循环缓冲区和用户负责锁定数据结构。那会解决你的问题 但是生产者-消费者风格的队列可能更适合您的问题。根据,迭代器应该保持有效。(在同时对容器进行变异和迭代时,我总是首先检查。)因此,您的示例代码是合法的 发生的情况是由于STL迭代器约定:
end()
不指向某个元素,而是指向最后一个元素之后的假想元素。第四次后推
,从itBegin
(第一个元素)到itEnd
(超过最后一个元素)的距离增加
一种解决方案可能是保持一个指向具体元素的迭代器,例如
itPenultimate = itEnd - 1;
现在,从
itBegin
到itpenutimate
的距离将保持不变,即使循环缓冲区被扩展,只要它不在该范围内。有可能push_back
使迭代器无效,从而使迭代器以UB结束。在给出的示例代码中,push_back
不会使任何迭代器无效。我(和OP)不明白为什么在容器上调用push_back
会导致局部变量itEnd
发生更改。@MooingDuckpush_back
在itEnd
之前插入了一个元素,从而导致从itBegin
到itEnd
的距离增加。如果在任意两个迭代器之间插入缓冲区,也会发生同样的情况。@MooingDuckcount
不会改变,而且itEnd
也不会改变。改变的是itEnd-itBegin
。这就像一个链子的两端,有人在中间插入一个链接。你是对的,坏例子。一个更好的澄清者是:为什么它的行为不像vector
/deque
/数组
?相反,它的行为类似于基于节点的容器boost::circular_buffer
看起来它应该像一个向量
/deque
/数组
。很好的解释,我最终使用boost::iterator_facade实现了一个自定义迭代器,它提供了我想要的行为。