如何用C ++编写缓存友好的多态代码?

时间:2011-03-10 14:27:45

标签: c++ caching polymorphism

我正在编写一段对性能有很高要求的代码,我需要以多态方式处理大量对象。假设我有一个A类和一个B类,它是从A派生的。我现在可以创建一个B的矢量:这样的

vector<A*> a(n);
for(int i = 0; i < n; i++)
  a[i] = new B();

但是如果n很大(在我的情况下按照10 ^ 6或更多的顺序),这将需要非常多的new调用,而且n个对象可能会遍布我的主内存,导致缓存性能非常差。处理这种情况的正确方法是什么?我正在考虑做类似以下的事情,让所有对象都在一个连续的内存区域。

B* b = new B[n];
vector<A*> a(n);
for(int i = 0; i < n; i++)
  a[i] = b + i;

但一个问题是如果b不再可用,如何释放新B [n]分配的内存(但我们仍然有)。我刚刚学会了尝试

delete[] a[0];

不是个好主意......

4 个答案:

答案 0 :(得分:7)

如果您确定那些只是B类型的对象,为什么不使用并行向量:

vector<B> storage(n);
vector<A*> pointers(n);
for(int i = 0; i < n; i++)
   pointers[i] = &storage[i];

答案 1 :(得分:2)

您可以使用placement new在特定的内存位置构建对象:

vector<A*> a(n);
for(int i = 0; i < n; i++)
  a[i] = new(storage + i*object_size) B();
  // and invoke the destructor manually to release the object (assuming A has a virtual destructor!)
  a[i]->~A(); 

但是你不能在不放弃连续存储的情况下解决'真实'问题:如果一个对象被释放,它将在堆中产生一个洞,从而导致一段时间内出现高度碎片。您只能跟踪释放的对象并重新使用存储。

答案 2 :(得分:1)

如果要将所有对象保留在连续内存中,同时避免使用间接(基类指针向量),则可以使用union样式容器,例如:向量boost::variant。当然,这将假设存在有限且已知数量的派生类,并且它们的大小是可比较的。缺点是向量的每个元素将占用与最大派生类一样多的内存,而不管它们的实际类(并且它还假设您的类合理地便宜复制)。优点是您在访问元素时具有多态对象的连续异构存储,类型安全性和无间接性。以下是boost::variant和三个类ABC的基本示例,其中BC都来自{{1}并且它们都是多态的(当然,这可能会更好一些糖涂层和/或更专门用于你的目的,而不是A这不适合这个目的):

boost::variant

答案 3 :(得分:0)

你只需要存储从new []某处返回的指针,然后再删除它们。例如,另一个向量。