在一些 C++ 项目中,我正在处理代表各种性质的图形的对象。它们都实现了一个通用的抽象接口,我将在这篇文章中将其简化为一个函数:
class graph {
public:
...
// Create an iterator over the successors of v
virtual succ_iterator* succ(const vertex* v) const = 0;
...
};
该类succ_iterator
也是一个抽象类,可以遍历 的后继顶点v
:
class succ_iterator {
public:
virtual void first() = 0; // reset the iterator
virtual void next() = 0; // move to next successor
virtual bool done() const = 0; // no more successor left?
virtual const vertex* dest() const = 0; // destination vertex
};
v
因此,对in graph的所有后继者的循环g
将如下所示:
succ_iterator* i = g->succ(v);
for (i->first(); !i->done(); i->next()) {
// use i->dest()
}
delete i;
我经常使用这样的循环来实现图形算法。分析代码表明它花费大量时间为这些微小的迭代器实例分配内存,所以我想听听改进它的想法。
不幸的是,我的图可能有非常不同的实现,所以每个图可能有自己的succ_iterator
接口实现。本质上,层次结构中的每个类在graph
层次结构中都有一个对应的类succ_iterator
。例如,可以使用一个图来std::vector
显式地存储邻接列表(在这种情况下,它succ_iterator
是上面的一个简单包装器std::vector::const_iterator
),而另一个图可能是即时计算的(在这种情况下,它的succ_iterator
实例实际上会随着它的进展计算后继者) )。我在编译时不知道图形的性质,因此这排除了template
基于 - 的实现à la STL。
我考虑过让每个图处理一个succ_iterator
. 这似乎需要一个额外的graph::succ_release(succ_iterator*)
方法来将迭代器返回到池中而不是删除它。我见过的大多数池都是在内存级别完成的:即,当你释放一个对象时,它的析构函数被调用,但占用的内存被保留,这样下一个对象将被创建(使用就地构造函数)在同一堵塞。看起来这仍然浪费时间,因为就地构造函数必须设置一个与前一个对象相同的虚拟表指针。我认为在这样的池中,我应该将delete
+替换为与构造函数具有相同原型new
的方法。recycle()
由于代码库非常大,这需要更改接口,在我实施之前,我想听听其他设计理念或可能的改进。
编辑:我不使用线程。