状态设计模式 - 不想删除成员类中的此指针
State Design Pattern - Don't want delete this pointer in member class
我使用下面的例子来实现一个状态设计模式。
https://sourcemaking.com/design_patterns/state/cpp/1我不想删除成员类中的*this指针,因为不安全(删除后我会调用其他成员函数)。
class ON: public State
{
public:
ON()
{
cout << " ON-ctor ";
};
~ON()
{
cout << " dtor-ONn";
};
void off(Machine *m);
};
class OFF: public State
{
public:
OFF()
{
cout << " OFF-ctor ";
};
~OFF()
{
cout << " dtor-OFFn";
};
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
}
有没有更好的方法来实现状态设计模式?我考虑过使用singleton,但是我想避免使用singleton。
问好,
链接的设计为:
- 状态机跟踪指向当前状态的指针。
- 当前状态负责在发生转换时设置新状态
- 通过创建新状态并指示机器改变指针 来实现。
- 一旦完成,它就会通过删除自己来自杀。
如本文所述,如果格外小心,这是可以工作的。您的代码符合先决条件。
另一种选择是状态机删除setCurrent()
中的当前状态。但更糟糕的是:一旦机器删除了对象,该对象就不再存在,因此当setCurrent()
返回时,您实际上处于与之前(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
}
状态转换将由状态机管理:
void Machine::check_transition() {
if (nextstate) {
swap (current, nextstate);
delete nextstate; // this contains the former current
nextstate = nullptr;
}
}
机器组织删除未使用的状态。注意,这种方法允许使用shared_ptr而不是原始指针。
这里有一个小的在线概念证明。
顺便说一句:机器析构函数也应该删除当前和下一个状态,以避免泄漏。在任何情况下,状态析构函数都应该定义为virtual
"…但我想避免使用单例。"
这可能是它们罕见的有效用例之一,因为状态本身应该无状态(这并不意味着它们不需要实例),并且无论当前状态机的上下文如何,都可以并发访问。
这就意味着你每次只需要一个状态的实例。
上述网站上显示的示例也会给您带来不必要的性能损失,其代价是每当状态发生变化时,new
和delete
都要付出代价,可以通过为状态提供稳定的static
实例来避免这种情况。
实际上你可以考虑像轻量级设计模式那样提供状态实例,它本质上归结为拥有单例状态实例。
但是,这要看情况。UML状态图实际上允许有非状态状态(作为具有历史属性的组合状态,或活动状态)。
看一下我的STTCL模板库概念文档,它解释了我开发模板库所使用的一些方面和设计决策,以及如何正确使用它。
请放心,我没有任何一个delete this;
在那里;-)。
我想说这个网站目前给出的例子,设计得真的很糟糕,一般不推荐1。
正如你所说,使用delete this
是不合适的,危险的,不可接受的。
当使用单例时,如果你手头有它们的有效用例。
1) 遗憾地注意到这一点,因为我一直使用它作为许多设计模式相关问题的"参考"。
- 如果基类包含双指针成员,则派生类的构造函数
- 如何创建存储指向成员函数的指针的类 (C++)
- decltype:使用指针访问类的静态成员
- 指针类型类成员的动态强制转换的恒定性是什么?
- 如何从另一个嵌套类中调用某个封闭类的嵌套类的函数指针成员的值?
- C++:私有类指针成员返回未定义的值
- 指向从指针派生类成员函数的指针,指向基类成员函数
- C++指向成员的指针的类内初始化会使 MSVC 失败(但 GCC/Clang 工作)
- C++ 类指针成员行为奇怪(错误)
- 通过智能指针向类成员进行赋值
- C++指针和类成员变量混淆
- 在类C++指针成员中
- C++ 包含唯一指针成员变量的类的赋值运算符
- 如何使用 QPoint 指针成员对类进行排队和取消排队
- C++:函数指针和类成员
- 是否可以从指向成员函数模板参数的指针推断类类型
- C 功能指针指向类成员
- 将函数指针成员模板限制为仅派生类
- 当通过引用传递包含指针成员的类对象时,为什么要多次调用析构函数?我该如何更正
- 使用指针创建类成员