c++:优化列表

C++: Optimized list

本文关键字:列表 优化 c++      更新时间:2023-10-16

对我的代码进行了一些深入的分析,发现它花了很多时间为向量分配空间。
对于大多数这些向量的大小是事先已知的,所以我调用reserve()来预先分配空间。对于大多数这些向量,大小几乎总是非常小-像4或5个元素,但在极少数情况下,它可以相当大。我想到的另一个优化是创建我自己的容器OptimizedList<T,N>。这个对象的一个实例本身包含N个T的实例,作为一个普通数组,如果用户试图添加超过N个项目,它将开始为额外的项目使用动态分配。

是否有已知的实现?

如何Qt的堆栈为基础的可变长度数组?

看起来与您的用例完美匹配,主要是小数组,将在堆栈上分配(最快的分配,只是一对指针上的add/sub指令)对于小数组,在堆上对于大数组。

我会考虑使用std::vector与自定义分配器优化4-5个元素(从池中提取)作为最简单和最可行的解决方案。这也是唯一的解决方案,我希望实际提供净收益。

使用std::deque可能没有帮助,尽管从教科书的角度来看似乎是这样。它可能真的很疼。deque减少了将数据从O(n)复制到O(1)的开销,但它们并不是神奇的无分配。相反,与使用vector相比,它们可能会导致更多的分配。
deque通常以向量的向量或循环缓冲区的形式实现。在后一种情况下,除了不能通过调用reserve() 来减轻它之外,您有与使用std::vector 完全相同的重新分配开销,并且在前一种情况下,您有两个分配,否则您只有一个。

将前几个对象直接嵌入到自定义向量类中,或者像Bgie的答案那样嵌入到堆栈上的变量数组中,这是非常诱人的,这确实是一个不太多不太大的向量的很好的解决方案。
然而,由于创建这些向量会产生性能问题,因此可以得出结论,您使用的不是5个或10个向量,而是许多个向量(否则就不重要了,它就无法测量!)。这意味着将数据放在堆栈上可能最终导致堆栈溢出。
然而,如果所有向量都是堆分配的,那么可能是一个很好的解决方案。在分配容器本身时,是否再分配几百字节并没有真正的区别,也没有溢出堆栈的风险。在这种情况下,你可以有效地节省一次分配。

因为你的大多数容器都很小,稀有的容器得到许多元素,我更喜欢std::deque。这可以帮助您以较低的价格避免不必要的重新分配。它没有reserve()方法,但由于大多数容器都很小,我认为它可以。

更重要的是,您应该检查包含在这些容器中的对象类型。我认为瓶颈不是重新分配本身,而是复制/破坏它的一部分。我怀疑"容器的值"复制构造函数和/或析构函数足够"重"。当构造函数/析构函数太复杂时,复制N个元素然后销毁旧的N个元素非常耗时。

作为最后的优化,我建议使用内存池/分配器来减少底层的malloc/realloc/free调用。