简体   繁体   English

C ++ - 指向对象的向量的向量性能,对象的性能

[英]C++ - Performance of vector of pointer to objects, vs performance of objects

In this case the question scenario is a game, so all resources are allocated at the beginning then iterated over for a level. 在这种情况下,问题场景是游戏,因此所有资源在开始时分配,然后迭代一个级别。

The objects being stored in the vector are instances of complex classes, and of course the actual copying them into the vector at load-time is time-consuming, but of low-concern. 存储在向量中的对象是复杂类的实例,当然在加载时将它们实际复制到向量中是耗时的,但是关注度低。

But if my main concern is the speed of iteration over the class objects at runtime, would I be better to store the class objects themselves in the vector, rather than just pointers to the class objects as is traditionally recommended? 但是如果我主要担心的是在运行时对类对象进行迭代的速度,那么我是否更好地将类对象本身存储在向量中,而不是像传统推荐的那样只指向类对象?

I am not worried about memory management in this example, only speed of iteration. 我不担心这个例子中的内存管理,只是迭代的速度。

I'm answering this question late, but the performance aspect is important and the answers online so far have been purely theoretical and/or focusing exclusively on the memory-management aspects. 我迟到了回答这个问题,但是性能方面很重要,到目前为止在线答案纯粹是理论上和/或专注于内存管理方面。 So here is some actual benchmarking info on three related scenarios I recently tried. 所以这里是我最近尝试的三个相关场景的一些实际基准信息。 Your results may be different but at least there's some idea of how things pan out in a practical application. 你的结果可能会有所不同,但至少有一些想法可以解决实际应用中的问题。

The class A referenced here has about 10 member fields, half of which are primitives and the other half are std::string , std::vector<int> , and other dynamically sized containers. 这里引用的类A有大约10个成员字段,其中一半是基元,另一半是std::stringstd::vector<int> ,以及其他动态大小的容器。 The application has already been fairly optimized and thus we would like to see which architecture now gives us the fastest looping over the collection of A . 该应用程序已经相当优化,因此我们希望看到哪个架构现在为我们提供了最快的A集合循环。 The values of any of A object's member fields may be changing over the application lifetime, but the number of A objects in the vector do not change over the many repeated iterations we perform (this continual iterating constitutes about 95% of this application's execution time). 任何A对象的成员字段的值可能会在应用程序生命周期中发生变化,但是向量中的A对象数量不会在我们执行的多次重复迭代中发生变化(此连续迭代构成此应用程序执行时间的约95%) 。 In all scenarios, looping was performed with the typical std::iterator or std::const_iterator . 在所有情况下,使用典型的std::iteratorstd::const_iterator执行循环。 Each enumerated A object has at least several member fields accessed. 每个枚举的A对象至少访问了几个成员字段。

Scenario 1 — Vector Of Object Pointers 场景1 - 对象指针向量

Although the simplest, this architecture of std::vector<A*> ended being slightly slower than the others. 尽管最简单, std::vector<A*>这种架构结束时比其他架构略慢。

Scenario 2 — Vector Of Object Pointers, Objects Are Allocated Using Placement New 场景2 - 对象指针向量,对象使用新的位置分配

The idea behind this approach is that we can improve the locality of caching by forcing our objects to be allocated into contiguous memory space. 这种方法背后的想法是我们可以通过强制将对象分配到连续的内存空间来改善缓存的局部性。 So the std::vector<A*> of object pointers is guaranteed to be contiguous by the std::vector implementation and the A objects themselves will also be contiguous on the heap because we've used the placement new idiom. 因此, std::vector<A*>对象指针的保证是由连续std::vector实现和A对象本身也将是连续的堆,因为我们使用了新的安置成语。 I used the same approach outlined in this answer ; 我使用了这个答案中概述的相同方法; more info on placement new can be found here . 有关安置新的更多信息,请点击此处

This scenario was 2.7% faster than Scenario 1. 此方案比方案1快2.7%。

Scenario 3 — Vector Of Objects 场景3 - 对象矢量

Here we use std::vector<A> directly. 这里我们直接使用std::vector<A> The std::vector implementation guarantees our A objects will be contiguous in memory. std::vector实现保证了我们的A对象在内存中是连续的。 Note that a std::vector of objects does involve considerations of the move and copy constructors of A . 请注意,对象的std::vector确实涉及A的移动和复制构造函数的注意事项。 To avoid unnecessary moving and/or reconstruction, it is best to std::vector.reserve() the maximum possibly needed size in advance (if possible) and then use std::vector.emplace_back() (instead of push_back() ) if at all possible. 为了避免不必要的移动和/或重建,最好std::vector.reserve()最大可能需要的大小(如果可能),然后使用std::vector.emplace_back() (而不是push_back() )如果可能的话。 Looping over this structure was the fastest because we are able to eliminate one level of pointer indirection. 循环这个结构是最快的,因为我们能够消除一个指针间接层。

This approach was 6.4% faster than Scenario 1. 这种方法比方案1快6.4%。

A related answer to a different question also shows that plain objects (as class members) can be quite faster than the respective pointers (as class members). 对不同问题的相关答案还表明,普通对象(作为类成员)可以比相应的指针(作为类成员)快得多。

The first thing is pointers should be used for storing bulky things . 第一件事就是指针应该用来存放笨重的东西。 Because if you use array of objects if would be creating n bulky objects and copy each one everytime its stored(it is also a big cost) And the second thing if you are using vectors(STL)The vectors size grows every time its gets full of memory. 因为如果使用对象数组,如果要创建n个庞大的对象并每次复制它们存储它(这也是一个很大的代价)而第二件事如果你使用向量(STL)每次向量大小增加记忆 The main cost is copying the data of first in second and this is actually the main cost ie copying. 主要成本是复制第一秒的数据,这实际上是主要成本,即复制。 Also this cost is minimal cost that would be incured if use built in. 此成本也是内置使用时可能产生的最低成本。

No, She is not wrong, she is absolutely right, though you are asking only about fast iteration, but that has alot of link with Memory... More the memory stack slower will be the access... 不,她没有错,她是绝对正确的,虽然你只询问快速迭代,但这有很多与内存的联系...更多内存堆栈将更慢访问...

I have a live demo... 我有一个现场演示......

#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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM