我应该使用哪个C++stl容器

Which C++ stl container should I use?

本文关键字:C++stl 容器 我应该      更新时间:2023-10-16

想象一下以下需求:

测量数据应该被记录下来,用户应该能够遍历数据。

uint32_t timestamp;
uint16_t place;
struct SomeData someData;
  • 在结构中有一个时间戳(uint32_t)、一个位置(uint16_t)和一些数据

  • 具有恒定数量的数据集。如果新的来了,最老的就扔掉。

  • "位置"的数量是动态的,用户可以在运行时插入新的

  • 应该可以通过数据迭代到下一个较新或较旧的数据集,但前提是位置是相同的

  • 只需要在末端插入

  • 应在程序启动时分配一次内存

  • 插入不需要很快,但不应该长时间阻塞其他线程,这些线程可能正在遍历容器

  • 内存需求应该是低

EDIT:-容器应该包含所有未使用的内存,因此它可能很大。

我不确定该用哪个容器。这是一个嵌入式系统,不应该使用升压等

我看到以下可能性:

std::vector-缺点:末尾的插入要求复制所有对象,在此期间,另一个线程无法访问vector。编辑:这可以通过将其实现为循环缓冲区来避免——请参阅下面的注释。在遍历向量时,我必须测试位置ID。也许将大量内存分配为一个块也可能是个问题,因为内存可能会被分割?

std::deque-与std::vector插入(和pop_back)相比更快,但内存需求?如果插入在末尾,则迭代程序不会变为无效。但我仍然需要迭代和测试第二个ID("place")。我认为它不需要像向量或数组那样在一个大块中分配所有内存。如果在前面添加一个元素,在后面删除另一个元素(或者先删除后添加),我想不会进行内存分配吗?

std::queue-我应该使用队列而不是deque?在许多实现中,队列确实是作为deque实现的吗?

std::map-与deque一样,现有元素的任何迭代器都不会变得无效。如果我将密钥设置为位置和时间戳的组合,那么通过地图的迭代可能会更快,因为它已经排序了?地图的内存需求?

std::multimap-由于位置的数量不是恒定的,我不能用"位置"作为索引进行多映射。

std::list-在这里对德克没有优势吗?

一些人建议使用循环缓冲区。如果我不想把内存分配成一个大块,我仍然必须使用容器,上面的大多数问题都是有效的。

更新:我将使用这里建议的环形缓冲区,但使用deque作为底层容器。为了能够用预选的"位置"快速滚动数据集,我最终将在数据结构中引入两个额外的索引,它们将指向同一位置的上一个和下一个索引。

将使用多少内存?在我的特殊情况下,结构的大小是56个字节。gnu-lib使用512字节作为最小块大小,IAR编译器使用16字节。因此,所使用的块大小将分别为512或56字节。除了两个迭代器(每个迭代器使用4个指针)和大小之外,每个块还将存储一个指针。因此,在iar编译器(块大小为56字节)的实现中,与使用std::矢量或数组相比,(在32位系统上)将有7%的开销。在gcc实现中,块中将容纳9个对象(504个字节),而每个块需要512+4个字节,这增加了2%。

块大小不大,但指针数组所需的连续内存大小已经相对较大,尤其是对于一个块就是一个结构的实现。

std::列表每个结构需要2个指针,在我的32位系统中,这是14%的开销。

  1. std::vector

    。。。记忆可以被分割吗?

    否,std::vector分配连续内存,如该链接中所述。数组也是连续的,但您也可以使用vector。

  2. std::deque是分段的,你说你不想要。还是要避免单个大的已分配块?目前还不清楚。

    无论如何,如果你真的想要一个循环缓冲区(因为你永远不会从前面/后面添加/删除元素),并且你无法控制块的大小,那么它对向量没有任何好处。

  3. std::queue

    。。。在许多实现中,队列确实是作为deque实现的吗?

    是的,这是所有实现中的默认值。请参阅链接的文档或任何像样的书籍。

    听起来你不想要FIFO队列,所以我不知道你为什么要考虑这个——接口不符合你的要求。

  4. 'std::map`

    。。。通过地图的迭代可能更快,因为它已经排序了?

    在大多数现代服务器/桌面架构上,map会更慢,因为推进迭代器涉及指针追逐(这会损害流水线)和可能的缓存丢失。您的匿名嵌入式架构可能对这些影响不太敏感,因此map对您来说可能更快。

    。。。地图的内存需求?

    更高。将节点大小(至少两个指针)添加到每个元素中。