【问题标题】:c++ container very efficient at adding elements to the endc ++容器在将元素添加到末尾时非常有效
【发布时间】:2015-06-09 15:04:46
【问题描述】:

我一直在运行一个用于科学目的的 c++ 程序,现在我正在考虑对其进行优化。

瓶颈似乎是我需要堆叠整数对的函数。他们的数量从一开始就不可能知道,我一直在使用一个自定义结构的std::vector,其中包含两个ints。是否有更有效的数据容器可以在末尾重复添加元素?我应该将它与两个 ints 一起使用,而不是一对或自定义结构吗?

编辑: 在对我的程序进行计时和分析之后,我可以说,就我的使用而言,vectordeque 稍快(仅快 3%)。我的外行结论是 CPU 很好地利用了数据的连续性。优化对我来说比以往任何时候都更神奇!对于那些可能会有所帮助的人:实际上,通过从 STL C++ 11 随机数生成器切换到 BOOST 生成器,我显着提高了运行时间。

【问题讨论】:

  • 您需要如何访问数据?您需要从前面、后面还是中间访问它?此信息对于确定要使用的容器很重要。
  • std::pair<int, int> 用于保存一对整数。您不需要制作自己的结构来保存它。至于选择快速附加的数据结构,这方面有很多内容。但最终,理论上快速的(例如链表)可能会被现代 CPU 缓存策略破坏,因此您可能必须尝试各种容器和基准测试,直到获得满意的解决方案。
  • std::vector<std::pair<int, int>> 很好,尝试在已知资源估计的情况下策略性地使用reserve,并避免破坏和重建向量。
  • @bastien 不一定。 std::list 将导致每个节点的动态内存分配,并且您的数据可能分散在您的内存中。 std::vector 在向量末尾有一个摊销的 O(1) 插入,当按顺序访问元素时,您将拥有更好的内存局部性。 (CPU 喜欢按顺序访问内存……)

标签: c++ vector containers


【解决方案1】:

您必须执行的对数重新分配的成本可以说是无关紧要的。但是,您可以考虑使用std::deque 来保证O(1) 在前面和末尾的插入。您将失去连续性,但 一些 缓存友好性得以保留。 deque 通常是一个不错的折衷方案,尤其是当您需要从前面弹出时。

还要考虑估计向量将存储的元素数量,并使用reserve。但请注意不要浪费太多内存,否则会产生相反的效果。

【讨论】:

  • 对此进行了很好的研究:codeproject.com/Articles/5425/…
  • 感谢您的建议,我将对两者进行基准测试,看看是否有改进。我虽然想调用储备,但后来我意识到我不知道最终大小的分布或平均值,并且在计时时使用非常大的值是低效的。非常感谢!!
  • 记住也要遵循@KerrekSB 的建议,即尽可能重用向量。
【解决方案2】:

正如 gd1 已经提到的,std::deque(双端队列)允许在两端快速插入和删除。此外,在双端队列的任一端插入和删除都不会使指针或引用无效。

在您的情况下,您可以使用 std::dequestd::pair(在 <utility> 中定义)来满足您的需求:

// Small example:
deque<pair<int, int>> deq;
deq.push_back({1234, 4321});
cout << deq.at(0).first << " " << deq.at(0).second;

// using 'at' above, should normally be inside a try block as it may throw 
// out_of_range exception

【讨论】:

    猜你喜欢
    • 2013-02-14
    • 1970-01-01
    • 2020-09-13
    • 1970-01-01
    • 2012-05-08
    • 1970-01-01
    • 2011-01-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多