对象容器的性能与指针容器的性能

时间:2015-03-09 18:38:15

标签: c++ pointers c++11 optimization containers

class C { ... };
std::vector<C> vc;
std::vector<C*> pvc;
std::vector<std::unique_ptr<C>> upvc;

根据C的大小,按值存储的方法或通过指针存储的方法将更有效。

是否可以大致知道这个大小是什么(在32位和64位平台上)?

3 个答案:

答案 0 :(得分:8)

是的,有可能 - 对它进行基准测试。由于现在CPU缓存如何工作,事情已经不再那么简单了。

查看Bjarne Stroustrup关于链接列表的讲座: https://www.youtube.com/watch?v=YQs6IC-vgmo

以下是Scott Meyers关于CPU缓存的精彩演讲:https://www.youtube.com/watch?v=WDIkqP4JbkE

答案 1 :(得分:5)

在得出任何结论之前,让我们先看一下每个例子的细节。

对象矢量

对象的向量首先具有初始性能。将对象添加到矢量时,它会复制。 当需要扩展保留内存时,向量也会复制。较大的对象将需要更多时间来复制,以及复杂或复合对象。

访问对象非常有效 - 只有一个解除引用。如果矢量可以放入处理器的数据缓存中,这将非常有效。

原始指针的矢量

这可能会影响初始化性能。如果对象在动态内存中,则必须首先初始化内存(已分配)。

将指针复制到矢量中不依赖于对象大小。这可能会节省性能,具体取决于对象大小。

访问对象会受到性能影响。在到达对象之前有2个差异。大多数处理器在加载数据缓存时不遵循指针。这可能会影响性能,因为处理器可能必须在取消引用指向对象的指针时重新加载数据高速缓存。

Smart Pointers的矢量

性能比原始指针贵一点。但是,当矢量被破坏时,将自动删除这些项目。必须删除原始指针才能销毁向量;或者创建内存泄漏。

摘要

最安全的版本是在向量中具有副本,但具有性能命中,具体取决于对象的大小和重新分配保留的内存区域的频率。由于双重解除引用,指针向量会获得性能命中,但在复制时不会产生额外的性能命中,因为指针的大小一致。与原始指针的向量相比,智能指针的向量可能需要额外的性能命中。

通过分析代码可以找到真相。在等待I / O操作(例如网络或文件I / O)时,一个数据结构与另一个数据结构的性能节省可能会消失。

可能需要执行大量数据结构的操作才能节省大量成本。例如,如果性能最差的数据结构与最佳数据结构之间的差异为10纳秒,则意味着您需要执行至少1E + 6次才能节省大量成本。如果第二个是重要的,则期望更多次访问数据结构(1E + 9)。

我建议选择一个数据结构并继续前进。开发代码的时间比程序运行的时间要多。安全性和稳健性也更重要。与安全可靠的版本相比,不安全的程序将消耗更多的时间来修复问题。

答案 2 :(得分:-1)

对于普通旧数据(POD)类型,该类型的向量总是比指向该类型的指针的向量更有效,至少直到sizeof(POD)&gt;的sizeof(POD *)。

几乎总是如此,POD类型至少在sizeof(POD)&gt;之前也是如此。 2 * sizeof(POD *),因为与动态分配要指向的对象相比,内存位置优越,总内存使用量更低。

这种分析将保持正确,直到sizeof(POD)超过您需要通过基准测试实验发现的体系结构,编译器和用法的某个阈值。以上仅为POD类型设置了该大小的下限。

很难对所有非POD类型说明任何确定性,因为它们的操作(例如 - 默认构造函数,复制构造函数,赋值等)可以像POD一样便宜或者任意更昂贵。 / p>