【问题标题】:What's the most efficient between vector and deque for the following use?对于以下用途,向量和双端队列之间最有效的是什么?
【发布时间】:2019-03-10 09:10:10
【问题描述】:

如果问题不是很详细,请提前抱歉,但这是一个非常具体的案例。

我想在一个非常像双端队列的容器中添加元素:我希望能够以有效的方式 push_back 和 pop_front。问题是,该容器将用于存储 SFML 库中的 sf::Vertex,因此要渲染它,我必须执行以下操作:

window.draw(&container[0], container.size(), sf::LineStrip)

这不适用于双端队列,因为双端队列的元素不是连续存储的。所以,由于我对内存使用了解不多,我正在考虑两种选择:

1) 使用双端队列并在渲染时复制向量中的元素:

std::deque<sf::Vertex> container; ... std::vector<sf::Vertex> buffer {container.front(), container.back()}; window.draw(&buffer[0], buffer.size(), sf::LineStrip};

2) 直接使用vector存储元素,并调用vec.erase(vec.begin());弹出第一个位置的元素

由于几乎每一帧都会调用 pop_front,我想知道哪种方法在内存方面的成本最低?

如果你有任何其他想法,我会接受它们:)

编辑:

所以这是我昨天晚上实现的:

https://github.com/grybouilli/SFML-sf-Vertex-FIFO-like-container src 和 hdr 文件中的主要代码:)

【问题讨论】:

  • 当您要求内存消耗效率时,vec.erase(vec.begin()); 不适合向量大小 IIRC。我不确定std::deque 是否旨在更好地做到这一点。至少std::vector 公开了一个函数shrink_to_fit(),它似乎承诺释放一些以前分配的内存。我不确定这是正确的操作(性能方面),应该在几乎每个渲染帧中调用。
  • 我可能会使用一个环形缓冲区,如果需要的话,调用 draw() 两次。但我也会尝试其他方法并衡量它们的性能。
  • 顶点的顺序重要吗?另外,立即释放内存有多重要? push/pop 的速度不是更重要吗?
  • 我要收集有关环形缓冲区的信息,这听起来是个好主意!是的,顶点的顺序很重要,因为在渲染它们时,我想将每个顶点与 Line 连接起来,我可以通过提供 sf::LineStrip 作为绘图调用的参数来做到这一点。由于我还要推送很多顶点,其中一些在某些时候甚至不会出现在屏幕上,而那些是我想要擦除的那些

标签: c++ vector sfml deque memory-efficient


【解决方案1】:

滚动你自己的容器:

  • 该类只是将向量包装为成员。或者,您可以私下从中派生。
  • 此外,您还要跟踪第一个有效元素的索引。弹出前面的元素只会增加该索引。请注意,这意味着实际调用 dtor 会被延迟,这假设它并不重要,低内存开销或没有内存开销。
  • 那些你需要的来自vector的方法被暴露了,要么通过简单的转发方法,要么通过using私下派生。
  • 在后面添加元素时,检查向量的容量和前面未使用的元素个数。使用它来决定何时刷新元素。

作为一种方法,首先找出您使用的矢量容器的接口。从你提到的有

  • size()
  • data()&amp;vec[0] 的拼写方式更具表现力)
  • push_back()
  • pop_front()

首先定义它们,使用下面的向量。然后,如果可行,请根据您的特定需求对其进行优化。

【讨论】:

  • 这是一个非常有趣的方法,我将尝试实现它并查看它的性能。谢谢!
  • 也许@Grybouilli 可以找到有用的sf::VertexArray implementation,按照建议,您可以创建一个类似的类,但具有双端队列行为。
猜你喜欢
  • 2013-03-14
  • 2012-03-27
  • 2016-06-04
  • 2012-09-07
  • 1970-01-01
  • 2014-10-14
  • 2011-07-17
  • 2015-05-01
  • 2018-12-05
相关资源
最近更新 更多