【发布时间】:2021-07-10 21:28:44
【问题描述】:
我正在尝试在 C++ 中实现 State 模式。
这里是一个示例代码:
#include <cstdio>
class Context;
class State {
public:
virtual ~State() = default;
explicit State(Context *context) : context_(context) {}
virtual void Print() = 0;
virtual void ChangeState() = 0;
protected:
Context *const context_;
};
class Context {
public:
void SwitchState(State *state) {
delete this->current_state_;
this->current_state_ = state;
}
State *GetCurrentState() const {
return this->current_state_;
}
private:
State *current_state_ = nullptr;
};
class FirstState : public State {
public:
explicit FirstState(Context *context) : State(context) {}
~FirstState() override {
printf("FirstState destructed. Address: %p\n", this);
}
void Print() override {
printf("First state print..\n");
}
void ChangeState() override;
};
class SecondState : public State {
public:
explicit SecondState(Context *context) : State(context) {}
void Print() override {
printf("Second state print..\n");
}
void ChangeState() override;
};
void FirstState::ChangeState() {
printf("First state changed to second state\n");
this->context_->SwitchState(new SecondState(this->context_));
printf("First state changed to first state\n");
this->context_->SwitchState(new FirstState(this->context_));
printf("First state changed to second state\n");
this->context_->SwitchState(new SecondState(this->context_));
}
void SecondState::ChangeState() {
this->context_->SwitchState(new FirstState(this->context_));
this->context_->SwitchState(new SecondState(this->context_));
this->context_->SwitchState(new FirstState(this->context_));
}
int main() {
Context context;
context.SwitchState(new FirstState(&context));
context.GetCurrentState()->Print();
context.GetCurrentState()->ChangeState();
context.GetCurrentState()->Print();
context.GetCurrentState()->ChangeState();
return 0;
}
我有一个分段错误错误,因为在这个实现中从State 调用Context::SwitchState 后,当前状态被删除,从 SwitchState 方法返回后我不能使用this,但有时我必须。
我尝试使用共享指针,它有点帮助,因为我不再遇到分段错误,但由于某种原因,状态的析构函数无论如何都会被调用。
我需要在切换状态时创建新的状态实例,因为我需要将一些参数传递给更改后的状态。
另外,我一般不知道如何解决这个问题,因为切换状态后所有对状态的引用都丢失了,只剩下引用是this。
我有一些不好的想法可以解决这个问题,但它们很丑陋,例如让SwitchState 只是保存新状态,并在状态中每个方法的末尾调用一些RealSwitchSavedState。我认为它会解决问题,因为在这种情况下,对状态的引用会一直保留到方法结束,但代码会很丑。
希望得到您的帮助! 提前致谢!
【问题讨论】:
-
"但由于某种原因,状态的析构函数仍然被调用" 你在
Context::SwitchState中调用delete this->current_state_。其中.. 删除状态,并调用其析构函数。而且,因为,本质上,您从State::ChangeState的实现中删除了调用该方法的状态-取消引用该状态的this是删除后的UB。仅使第一个Context::SwitchState调用非UB。在我看来,最好的办法是重新思考整个关系架构。 -
将
this->context_保存在FirstState::ChangeState顶部的局部变量中,将该变量用于后续SwitchState调用,因此您无需触摸this。仍然是一个非常脆弱的设计,但它会解决你眼前的问题。 -
@AlgirdasPreidžius,是的,我知道为什么会这样,但我想找到具有相同架构的最佳解决方案,因为在 Java 中我可以轻松实现它,在 C++ 中我面临这个问题。跨度>
-
@IgorTandetnik,谢谢,但在真实代码中,我需要访问完整的对象状态,而不仅仅是上下文。我现在可以将需要的数据保存到局部变量中,但这不是最佳解决方案
-
暂时忘记您的代码。你能用语言解释应该发生什么吗?特别是
SwitchState为什么逻辑一致,不涉及*this的销毁?
标签: c++ oop memory design-patterns state-pattern