我正在编写一段对性能有很高要求的代码,我需要以多态方式处理大量对象。假设我有一个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];
不是个好主意......
答案 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
和三个类A
,B
,C
的基本示例,其中B
和C
都来自{{1}并且它们都是多态的(当然,这可能会更好一些糖涂层和/或更专门用于你的目的,而不是A
这不适合这个目的):
boost::variant
答案 3 :(得分:0)
你只需要存储从new []某处返回的指针,然后再删除它们。例如,另一个向量。