状态设计模式 - 不要在成员类中删除此指针

时间:2015-06-09 20:03:28

标签: c++ design-patterns

我使用下面的例子来实现状态设计模式。

https://sourcemaking.com/design_patterns/state/cpp/1

我不想删除成员类中的* this指针因为不安全(我会在删除后调用其他成员函数)。

class ON: public State
{
  public:
    ON()
    {
        cout << "   ON-ctor ";
    };
    ~ON()
    {
        cout << "   dtor-ON\n";
    };
    void off(Machine *m);
};

class OFF: public State
{
  public:
    OFF()
    {
        cout << "   OFF-ctor ";
    };
    ~OFF()
    {
        cout << "   dtor-OFF\n";
    };
    void on(Machine *m)
    {
        cout << "   going from OFF to ON";
        m->setCurrent(new ON());
        delete this; // <<< This line looks suspect and unsafe
    }
};
void ON::off(Machine *m)
{
  cout << "   going from ON to OFF";
  m->setCurrent(new OFF());
  delete this; // <<< This line looks suspect and unsafe
}

有没有更好的方法来实现状态设计模式?我想过使用单身人士,但我想避免使用单身人士。

致以最诚挚的问候,

2 个答案:

答案 0 :(得分:2)

  

&#34; ...但我想避免使用单身人士。&#34;

这可能是他们罕见的有效用例之一,因为状态应该是无状态本身(这并不代表他们不需要实例),以及无论当前状态机的上下文如何,都可以同时访问 这意味着你实际上一次只需要一个状态的实例。

上述网站上显示的示例也会给您带来不必要的性能影响,只要状态发生变化,newdelete就会产生不必要的性能损失,这可以避免稳定{{1}州的实例。

实际上,您可以考虑像Flyweight Design Pattern一样提供状态实例,这实际上归结为 Singleton 状态实例。

但是,这取决于。 UML状态图实际上允许具有非无状态状态(具有历史属性或活动状态的复合状态)。

查看我的STTCL template library concept document,它解释了我用过的一些方面和设计决策,开发模板库以及如何正确使用它。
请放心,我在那里没有任何单static; - )。

我说网站目前提供的示例,设计非常糟糕,一般不推荐 1
正如您所提到的,使用delete this;并不合适,危险且不可接受。

使用 Singleton 时,如果您手边有有效的用例。

1) 可悲地注意到这一点,因为我已经将它作为&#34;参考&#34; 用于许多{ {3}}此处有相关问题。

答案 1 :(得分:2)

您的链接中使用的设计是:

  • 状态机跟踪指向当前状态的指针。
  • 当转换发生时,当前状态负责设置新状态
  • 它通过创建新状态并指示机器更改指针
  • 来实现
  • 一旦完成,它就会通过删除自己来自杀。

正如here所述,如果采取额外的谨慎措施,这可能会有效。您的代码尊重先决条件。

另一种方法是状态机删除setCurrent()中的当前状态。但更糟糕的是:一旦机器删除了对象,该对象就不再存在,因此当setCurrent()返回时,您事实上处于与以前相同(危险)的情况下(使用{ {1}}),重要的区别在于这并不明显。

修改

如果您对此构造感到不自在,可以选择变体:

delete this

在这种情况下,需要稍微更新状态机功能:

class Machine
{
   class State *current;     // current state
   class State *nextstate;   // null, unless a state transition was requested
   void check_transition();  // organise switch to nextstate if transition is needed 
public:
    Machine();
    void setCurrent(State *s)
    {
        nextstate = s;  // only sets the info about nextstate 
    }
    void set_on();
    void set_off();
}; 

然后状态机将管理状态转换:

void Machine::set_on()
{
   current->set_on(this);  // as before
   check_transition();     // organise the transition if the transition was requested
}

机器组织删除未使用的状态。请注意,此方法允许使用shared_ptr而不是原始指针。

这里有一个小online proof of concept

顺便说一下:机器析构函数还应该删除当前和下一个状态,以免泄漏。无论如何,状态析构函数应该被定义为虚拟