想象一下以下要求:
应该记录测量数据,并且用户应该能够遍历数据。
uint32_t timestamp;
uint16_t place;
struct SomeData someData;
在结构中具有时间戳记(uint32_t
,位置(uint16_t
)和一些数据
具有恒定数量的数据集。如果有新的,最旧的被扔掉。
“位置”的数量是动态的,用户可以在运行时插入新的
应该有可能遍历数据到下一个新的或更旧的数据集,但前提是位置相同
仅需在末尾插入
内存应在程序启动时分配一次
插入不必很快,但不应长时间阻塞可能正在容器中迭代的其他线程
内存需求应该低
编辑:-容器应存储否则不使用的所有内存,因此它可能很大。
我不确定应该使用哪个容器。这是一个嵌入式系统,不应使用boost等。
我看到以下可能性:
std :: vector-缺点:最后插入需要复制所有对象,在此期间,另一个线程无法访问该向量。编辑:这可以通过将其实现为循环缓冲区来避免-参见下面的注释。当遍历向量时,我必须测试地点ID。将一个内存分配为一个块也许也可能是一个问题-因为内存可以分段?
std::deque
-与std::vector
插入(和pop_back
)相比更快,但是需要内存吗?如果插入在末尾,则迭代器不会变得无效。但是我仍然必须迭代并测试第二个ID(“位置”)。我认为不需要像矢量或数组那样在一个大块中分配所有内存。如果在前面添加一个元素,然后在末尾删除另一个元素(或先删除然后添加),我猜是否没有发生内存分配?
std::queue
-我应该使用队列而不是双端队列?确实在许多实现中,队列生成器就像双端队列一样受到威胁吗?
std::map
-像双端队列一样,现有元素的任何迭代器都不会失效。如果我将键组合为位置和时间戳,那么遍历地图的迭代速度可能会更快,因为它已经排序了?地图的内存需求?
std::multimap
-由于位数不是恒定的,因此我无法以“ place”作为索引来制作多图。
std::list
-在这里比双端队列没有优势吗?
有人建议使用循环缓冲区。如果我不希望将内存分配为一个大块,我仍然必须使用容器,并且上面的大多数问题仍然有效。
更新: 我将按照此处的建议使用环形缓冲区,但使用双端队列作为基础容器。为了能够快速滚动带有预选“位置”的数据集,我最终将在数据结构中引入两个附加索引,这些索引将指向具有相同位置的上一个和下一个索引。
将使用多少内存?在我的特殊情况下,该结构的大小为56个字节。 gnu lib使用512字节作为最小块大小,IAR编译器使用16字节。因此,使用的块大小将分别为512或56个字节。除了两个迭代器(每个使用4个指针)和大小外,每个块还将存储一个指针。因此,与使用std :: vector或数组相比,在iar编译器(块大小为56字节)的实现中,开销(在32位系统上)为7%。在gcc实现中,该块中可容纳9个对象(504字节),而每个块需要512 + 4字节,这要多2%。
块大小不大,但是指针数组所需的连续内存大小已经相当大,尤其是对于其中一个块是一个结构的实现。
一个std :: list每个结构将需要2个指针,在我的情况下,在32位系统上,这是14%的开销。
答案 0 :(得分:0)
...内存是否可以分段?
否,std::vector
分配连续的内存,如该链接中所述。数组也是连续的,但是您也可以使用向量。
std::deque
是分段的,您说过不需要。还是要避免分配单个大块?还不清楚。
无论如何,如果您真的想要一个圆形缓冲区,它比矢量没有任何好处(因为无论如何您永远都不会从前/后添加/删除元素),并且您无法控制块的大小。
...在许多实现中,队列是否像双端队列一样被设置为真的?
是的,这是 all 实现中的默认设置。请参阅链接的文档或任何体面的书。
听起来好像不想要FIFO队列,所以我不知道为什么要考虑这个队列-接口不符合您的要求。
...通过地图迭代可能更快,因为它已经排序了?
在大多数现代服务器/桌面体系结构上,映射将较慢,因为推进迭代器会涉及指针追逐(这会损害流水线操作)和可能的高速缓存未命中。您的匿名嵌入式体系结构 可能对这些影响不太敏感,因此地图 可能对您更快。
...地图的内存需求?
更高。您已将节点大小(至少两个指针)添加到每个元素。