【问题标题】:Move large member object out of class?将大型成员对象移出课堂?
【发布时间】:2015-10-03 19:32:05
【问题描述】:

背景/示例:

我目前有一个类似以下的课程:

class Element {
  Large l1;
  OtherLarge l2;
  Small s1;
  VerySmall s2;
};

其中LargeOtherLarge 相对较大(约80 字节),而SmallVerySmall 相对较小(约4 到16 字节)。

在这些元素上,我有两种操作方式:

  • 以各种方式对它们进行排序。在此期间,只有成员 s1s2 可以访问/需要。
  • 以各种方式组合大成员(例如矩阵-矩阵乘法)。

第二类操作已经相当快并且可以很容易地并行化,因此我想进一步加快第一类操作。与另一个类 Element2 相比,我用 8 字节整数替换了两个大数据成员,什么都不做告诉我,如果我能以某种方式将直接数据成员 l1l2 替换为一种或另一种动态的指针- 在别处分配元素,我已经大获全胜了。

作为参考,所有成员类型都有复制和移动构造函数,并且可以复制和移动,但移动它们要便宜得多。 LargeOtherLarge 也会自己分配大量内存,所以分配多一点并不一定很糟糕。

具体问题

是否可以,如果可以,最好的方法是用指向其他地方动态分配对象的指针替换类的直接成员对象;尽可能地保留直接成员的行为 w.r.t 构造、销毁、成员变量访问等?如果我天真地使用std::unique_ptr<Large>,我想我将不得不取消对它的一半时间/特别注意复制?理想情况下,我希望新成员对象的行为就像旧的大成员对象仍然存在一样。

【问题讨论】:

  • 所以基本上,你想减小Element的大小?
  • 如果我是你,我会测试一下。您可能会对结果感到惊讶。缓存局部性会对性能造成巨大影响,160 字节并不是很大。如果元素数量不是很大,您可以使用不同的排序算法来减少元素移动而不是比较。
  • 您是否考虑过使用 shared_ptr 代替?
  • 是的,没错,我想减小元素本身的大小。 @CemKalyoncu 不幸的是,它确实有很大的效果,如果我用整数替换大元素(并且仍然不使用它们),事情会变得更快,因为我最多可以将 4 个 Elements 放入单个缓存行(而不是每个元素使用两个)。我不太确定为什么 shared_ptr 会有所帮助,据我所知,不需要引用计数。
  • 关于算法的不同选择:每个单独的排序调用仅适用于 20 到 50 个元素,但这必须在代码的串行区域中经常发生。小尺寸意味着某种设置首先工作(我遍历元素并挑选所需的数据成员)或更智能的算法使用 O(log(n)n) 而不是当前的 O(n²)没有多大帮助。显然我想避免重做所有事情,因此是影响最小的问题。

标签: c++ class c++11 memory


【解决方案1】:

unique_ptr 不会解决您的问题,因为排序可能涉及复制(用于交换)。我相当确定享元模式可以解决您的问题。这是一个简单的实现:

class Element_data {
public:
    large l1,l2;
};

std::vector<Element_data> data;

class Element {
public:
   small s1, s2;
   int data_ind;

   large &GetLarge1() { 
       assert(data_ind>=0 && data_ind<data.size);
       return data[data_ind].l1; 
   }
};

std::vector<Element> elements;
...
std::sort(elements.begin(), elements.end(), &mysortfn);

为什么不使用指针?如果您向数据向量添加新成员,它们可能会失效。此外,这种方法允许您将数据保存在一起,以便更容易将其加载到缓存中。

补充要点:

  • 如果您要永久删除元素,则还应删除数据。
  • 添加新成员非常简单
  • 在排序或其他一些操作时,让多个元素指向相同的数据是安全的

编辑:为了确保在不清楚时不会遇到问题,Element 的析构函数不应破坏数据。您可以为此提供自定义删除器。最好的方法是开发一个可以执行此操作的容器,使用擦除功能擦除元素和数据。

【讨论】:

  • 你的意思是std::vector&lt;Element_data&gt; data
  • @MariusBancila 完全正确,已修复。
  • 嗯,是的。将其重建为 struct-of-arrays 而不是 array-of-structs 可能是最快的,但也会使某些地方的代码更加难看。在主数组的结构中保留对其他数组的索引似乎是一个不错的中间立场。我会再考虑一下,然后等一天左右可能会有更多答案,但总的来说,我担心这是我能得到的最接近的结果。谢谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多