我有一个对象的成员函数,通常以迭代方式使用,但偶尔以递归方式使用。该功能基本上遵循下坡水流的路径,并且在某些条件下流可能分裂。为了支持偶尔的递归,我必须将对象的状态推入堆栈并在之后将其弹出。我目前正在使用局部变量,但代码看起来很糟糕。我想写PushState和PopState成员,但我看过的大部分实现都不是很好。例如在我的对象中使用堆栈成员,最终使用堆慢,导致其他问题。当push函数返回时,_alloca将无法正常工作,因为堆栈帧会丢失。
是否有任何其他合理的通用方法可以从堆栈中推送和弹出我错过的内容?
class CMyObject
{
enum Direction
{
left,right,branch,finished;
}
// state variables
double m_XPos,m_YPos;
void Navigate(double x,double y);
Direction GoLeft();
Direction GoLeft();
};
void CMyObject::Navigate(double x,double y)
{
m_XPos = x; m_YPos = y;
Direction d = GoLeft(x,y);
while(d != finished)
{
switch(d)
{
case left: d = GoLeft(); break;
case right: d = GoRight(); break;
case branch:
{
// push object state onto the stack
double temp_x = m_XPos; double temp_y = m_YPos;
Navigate(m_XPos,m_YPos);
// pop object state from the stack
m_XPos = temp_x; m_YPos = temp_x;
GoRight();
} break;
}
}
}
答案 0 :(得分:2)
我想显而易见的方法是创建整个对象的副本并对其进行递归调用。这样,每个分支都有自己的状态,编译器会为您执行堆栈管理。基本上,方法必须是reentrant才能安全地用于递归。这不是这种情况,因为您的方法依赖于持久状态。所以你必须复制那个状态,这意味着复制对象。
<强>更新强>
有关递归和重入的更多链接:
答案 1 :(得分:1)
我认为你可能需要两个对象 - 一个维护位置和任何其他状态,另一个通过树对第一个对象的实例进行递归导航。这样,当导航器中的递归调用返回时,将恢复导航对象的状态。
答案 2 :(得分:0)
这样的事情怎么样?
struct Restore {
Restore(double& value) : m_value(value), m_initial(value) {}
~Restore() {m_value = value;}
double& m_value;
double m_initial;
};
然后:
{ //scope
Restore r1(m_XPos), r2(m_YPos);
Navigate(m_XPos,m_YPos);
} // m_XPos and m_YPos automatically restored when r1 and r2 goes out of scope