基本上我正在创建一个基类,它将用于存储为链表的类,这些类会被一个返回bool的虚拟更新()函数所规定的遍历和删除。
我想知道这是否是最有效的案例(我喜欢这个事实,特别是它可以是一个单一的链表):
class Traversable
{
public:
Traversable();
virtual ~Traversable();
void traverse(Traversable** prevNext);
virtual bool update()=0;
protected:
private:
Traversable* next;
};
void Traversable::traverse(Traversable** prevNext)
{
if (!update()) /// Virtual function that returns a death flag
{ /// Death
if (next)
{
Traversable* localNext = next;
delete this;
localNext->traverse(prevNext);
}
else
{
*prevNext = NULL;
delete this;
}
}
else
{ /// This node stays alive, for now
*prevNext = this;
if (next)
{
next->traverse(&next);
}
}
}
请注意,链接列表以NULL结尾。
我认为在调用下一个遍历函数后,对局部变量的仔细缺乏分配操作将确保使用尾调用来使用此函数。任何人都可以发现我做错的任何事情,或者可能暗示一种稍微不那么复杂的方法:p
答案 0 :(得分:1)
你故意混淆代码,以“诱惑”编译器创建特定的结果;这种情况是否发生很可能更依赖于所使用的编译器,有效的优化标志,甚至是使用上述编译的代码。以下是更紧凑的代码:
void Traversable::traverse(Traversable** prevNext)
{
bool doUpdate = update();
*prevNext = doUpdate ? this : next ? *prevNext : NULL;
Traversable **argNext = doUpdate ? &next : prevNext;
Traversable *localNext = next;
do_the_traversal_action(); // not spec'ed ...
if (!doUpdate)
delete this;
if (localNext)
localNext->traverse(argNext);
}
并且仍然以单个尾部返回点结束该函数。使用条件的唯一原因是因为您正在更改prevNext
。
编辑:我想说的是,无论你如何编码,最终由编译器决定是否要对函数进行尾部优化。对于现代优化编译器,通常在GCC中切换(-fconserve-stack
或-foptimize-sibling-calls
)对源代码本身的影响更大。
编辑2:是的,如果当然可以非递归地编写此函数;最后,它只是一种访客类型模式。所以实际的活动最终会像:
static void Traversable::traverse(Traversable *start)
{
Traversable *cur, *next;
for (cur = start; cur; cur = next) {
next = cur->next;
cur->do_the_traversal_action(); // not spec'ed ...
if (cur->update())
continue; // not supposed to remove this
if (next)
next->prevNext = cur->prevNext; // remove cur from list
delete cur;
}
}
虽然,当你这样编码时,下一个显而易见的问题是,为什么不为Traversable
实现简单的迭代器类型,并使用std::remove_copy_if()
进行访问和删除条件任务。或者使用STL列表开始。