[英]C++ - Performance of vector of pointer to objects, vs performance of objects
在这种情况下,问题场景是游戏,因此所有资源在开始时分配,然后迭代一个级别。
存储在向量中的对象是复杂类的实例,当然在加载时将它们实际复制到向量中是耗时的,但是关注度低。
但是如果我主要担心的是在运行时对类对象进行迭代的速度,那么我是否更好地将类对象本身存储在向量中,而不是像传统推荐的那样只指向类对象?
我不担心这个例子中的内存管理,只是迭代的速度。
我迟到了回答这个问题,但是性能方面很重要,到目前为止在线答案纯粹是理论上和/或专注于内存管理方面。 所以这里是我最近尝试的三个相关场景的一些实际基准信息。 你的结果可能会有所不同,但至少有一些想法可以解决实际应用中的问题。
这里引用的类A
有大约10个成员字段,其中一半是基元,另一半是std::string
, std::vector<int>
,以及其他动态大小的容器。 该应用程序已经相当优化,因此我们希望看到哪个架构现在为我们提供了最快的A
集合循环。 任何A
对象的成员字段的值可能会在应用程序生命周期中发生变化,但是向量中的A
对象数量不会在我们执行的多次重复迭代中发生变化(此连续迭代构成此应用程序执行时间的约95%) 。 在所有情况下,使用典型的std::iterator
或std::const_iterator
执行循环。 每个枚举的A
对象至少访问了几个成员字段。
场景1 - 对象指针向量
尽管最简单, std::vector<A*>
这种架构结束时比其他架构略慢。
场景2 - 对象指针向量,对象使用新的位置分配
这种方法背后的想法是我们可以通过强制将对象分配到连续的内存空间来改善缓存的局部性。 因此, std::vector<A*>
对象指针的保证是由连续std::vector
实现和A
对象本身也将是连续的堆,因为我们使用了新的安置成语。 我使用了这个答案中概述的相同方法; 有关安置新的更多信息,请点击此处 。
此方案比方案1快2.7%。
场景3 - 对象矢量
这里我们直接使用std::vector<A>
。 std::vector
实现保证了我们的A
对象在内存中是连续的。 请注意,对象的std::vector
确实涉及A
的移动和复制构造函数的注意事项。 为了避免不必要的移动和/或重建,最好std::vector.reserve()
最大可能需要的大小(如果可能),然后使用std::vector.emplace_back()
(而不是push_back()
)如果可能的话。 循环这个结构是最快的,因为我们能够消除一个指针间接层。
这种方法比方案1快6.4%。
对不同问题的相关答案还表明,普通对象(作为类成员)可以比相应的指针(作为类成员)快得多。
第一件事就是指针应该用来存放笨重的东西。 因为如果使用对象数组,如果要创建n个庞大的对象并每次复制它们存储它(这也是一个很大的代价)而第二件事如果你使用向量(STL)每次向量大小增加记忆 主要成本是复制第一秒的数据,这实际上是主要成本,即复制。 此成本也是内置使用时可能产生的最低成本。
不,她没有错,她是绝对正确的,虽然你只询问快速迭代,但这有很多与内存的联系...更多内存堆栈将更慢访问...
我有一个现场演示......
#include <iostream>
#include <string>
#include <vector>
#include "CHRTimer.h"
struct Items
{
std::string name;
int id;
float value;
float quantity;
};
void main()
{
std::vector<Items> vecItems1;
for(int i = 0; i < 10000; i++)
{
Items newItem;
newItem.name = "Testing";
newItem.id = i + 1;
newItem.value = 10.00;
newItem.quantity = 1.00;
vecItems1.push_back(newItem);
}
CHRTimer g_timer;
g_timer.Reset();
g_timer.Start();
for(int i = 0; i < 10000; i++)
{
Items currentItem = vecItems1[i];
}
g_timer.Stop();
float elapsedTime1 = g_timer.GetElapsedSeconds();
std::cout << "Time Taken to load Info from Vector of 10000 Objects -> " << elapsedTime1 << std::endl;
std::vector<Items*> vecItems;
for(int i = 0; i < 100000; i++)
{
Items *newItem = new Items();
newItem->name = "Testing";
newItem->id = i + 1;
newItem->value = 10.00;
newItem->quantity = 1.00;
vecItems.push_back(newItem);
}
g_timer.Reset();
g_timer.Start();
for(int i = 0; i < 100000; i++)
{
Items *currentItem = vecItems[i];
}
g_timer.Stop();
float elapsedTime = g_timer.GetElapsedSeconds();
std::cout << "\nTime Taken to load Info from Vector of 100000 pointers of Objects -> " << elapsedTime;
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.