【发布时间】:2019-04-10 19:43:51
【问题描述】:
我正在创建一个状态机,其中几个状态正在enter() 方法中将机器切换到新的(下一个)状态。状态是 unique_ptr 对象,根据需要创建并提供给机器。
由于某些状态在 enter() 方法中切换到下一个状态(因此,在使用时),我担心这里可能出现问题 - 当当前状态调用 set_state() 时,状态机为其 @987654326 分配一个新状态@ 成员因此丢失了指向进行此调用的状态的唯一指针。
下面是我关心的一个例子 - obj A 和 B 的唯一 unique_ptr 设置为指向 C,同时从 A 然后 B 递归调用此操作。这可靠吗?会不会有什么问题?
#include <memory>
#include <iostream>
class IState;
class IStateMachine {
public:
virtual ~IStateMachine() = default;
virtual void set_state(std::unique_ptr<IState> new_state) = 0;
};
class IState {
public:
virtual ~IState() = default;
virtual void enter(IStateMachine&) = 0;
};
class StateC : public IState {
public:
void enter(IStateMachine&) override {
std::cout << __func__ << ": StateC - start" << std::endl;
std::cout << __func__ << ": StateC - end" << std::endl;
}
};
class StateB : public IState {
public:
void enter(IStateMachine& sm) override {
std::cout << __func__ << ": StateB - start" << std::endl;
sm.set_state(std::make_unique<StateC>());
std::cout << __func__ << ": StateB - end" << std::endl;
}
};
class StateA : public IState {
public:
void enter(IStateMachine& sm) override {
std::cout << __func__ << ": StateA - start" << std::endl;
sm.set_state(std::make_unique<StateB>());
std::cout << __func__ << ": StateA - end" << std::endl;
}
};
class StateMachine : public IStateMachine {
public:
void start() {
set_state(std::make_unique<StateA>());
}
void set_state(std::unique_ptr<IState> new_state) {
state_ = std::move(new_state);
state_->enter(*this);
}
std::unique_ptr<IState> state_;
};
int main()
{
StateMachine sm;
sm.start();
}
代码输出:
enter: StateA - start
enter: StateB - start
enter: StateC - start
enter: StateC - end
enter: StateB - end
enter: StateA - end
编辑 1:
背后的主要思想是状态根据需要创建,并在不再需要后自动销毁。
限制是状态可以在其enter() 方法中做一些工作,然后在该方法结束时将状态机切换到下一个状态。
编辑 2:
我没有明确删除该对象。我的问题更多的是关于 unique_ptr 指向的对象的生命周期,以防从对象自己的方法(递归)分配给这个 unique_ptr 的新对象(参见示例代码)。
【问题讨论】:
-
官方称其为未定义行为,但由于您在删除后无法访问任何成员,因此它可能适用于大多数平台
-
this在调用sm.set_state后悬空,这本身不是 UB。但是在thisdangles 时引用类内的任何内容都是UB。无论如何看起来都是糟糕的设计。 -
如果你能在这里解释更多关于糟糕设计的信息,我将不胜感激,并可能提出改进的方法。我在问题的底部添加了我的意图。
-
你可以让 set_state() 返回之前的状态。然后调用者可以决定自己的生命周期。
-
“我不认为它是重复的”。我看不出显式删除 this 或通过 unique_ptr 删除之间的区别。 is delete this allowed 中的一些答案也谈到了这一点
标签: c++ unique-ptr state-machine