【问题标题】:C++ : vector of vector and cache localityC ++:向量和缓存位置的向量
【发布时间】:2017-02-14 15:36:25
【问题描述】:

我正在寻找一个库/解决方案,以减轻我在程序中遇到的相当重要的缓存未命中次数

class Foo{
    std::vector<Foo*> myVec;

    // Rest of the class
};

int main(){
     // Some code
     std::vector<Foo*> myVecOfFoo;
}

所以,我做的第一件事是创建一个std::vector&lt;Foo&gt;,每个Foo* 都指向这个向量。它有很大帮助。 我的主要问题是std::vector&lt;Foo*&gt; myVec;。这些向量的每个内部数组都位于内存的不同部分。就像我创建了一个 std::vector&lt;Foo&gt; 以便我所有的 Foo 在内存中是连续的一样,我希望我的所有 std::vector&lt;Foo*&gt; myVec; 在内存中对齐(实际上是内部数组)。怎么样?

注意:重要的一点是myVec 的大小因Foo 的实例而异。否则我可以简单地构建一个std::vector&lt;Foo*&gt; 并编写getter/setter。另外,我有std::shared_ptr&lt;Foo&gt; 而不是Foo*,因为我不是野蛮人,但这使对示例的理解更容易。最后,我保证所有权形成一个 DAG,所以我的共享指针中没有循环。

【问题讨论】:

  • 嗯,通过可变大小获取连续内存可能很困难。如果这很重要,我可能会考虑竞技场分配。
  • 我能想到的一件事是使用自定义分配器将所有数据一起存储在内存中。这样做虽然会限制您可以拥有多少 Foo
  • 看看boost的small_vector
  • 向量没有提示命令,使其大小保持在提示边界内或只是强制其父类扩展?
  • 如果您不知道Foo 的最大实例数,那么您将不得不考虑当您需要增加连续存储以容纳新实例时会发生什么。任何幼稚的实现都会使所有引用、迭代器和指向Foo 的所有实例的指针无效。当破坏Foo 的实例时,会出现额外的复杂情况,从而在您的存储中留下漏洞(如果这很重要)。也许可以使用代理类,存储Foo 实例的index,但随后您引入了一个可能无法接受的新间接级别。

标签: c++ vector cache-locality


【解决方案1】:

用一对替换std::vector&lt;Foo*&gt;

std::vector<Foo*>::const_iterator begin;
std::vector<Foo*>::const_iterator end;

创建一个std::vector&lt;Foo*&gt;,并将所有指针放入其中。然后通过设置beginend 迭代器,将指向Foo 各个实例的连续指针块打包出来。

这可能需要预处理步骤,当您使用 std::vector&lt;Foo*&gt; 从“节点”类的实例构建图形时,例如

class FooNode {
    Foo *myFoo;
    std::vector<Foo*> myVec;
};

一旦你的节点连接起来,遍历图表,并将myVecs 收集到一个大向量中。完成所有单个向量后,再次遍历初步图形,并将beginend 位置设置为myFoos。您可以通过将FooNode 向量的大小添加到当前位置来计算位置。只要您在图表中的走动是相同的,这将起作用。

【讨论】:

  • 我真的很喜欢这个答案,但 Francois Andrieux 提到,如果我在 std::vector&lt;Foo*&gt; 中添加超出容量的项目,每个迭代器都会失效
  • @Fezvez 没错!这正是您的结构在预处理步骤结束后必须保持静态的原因。我添加了更多关于从 FooNodes 构建图形的细节,这会推迟从向量中获取迭代器,直到您确定不会有进一步的修改。
猜你喜欢
  • 2014-01-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-06
  • 2017-12-05
  • 2021-11-09
  • 1970-01-01
  • 2020-09-26
相关资源
最近更新 更多