【发布时间】:2021-11-18 04:42:40
【问题描述】:
我遇到了一些问题,我在管理类中存储的类实例没有保留它们的数据。我在这里将我正在努力解决的核心概念写成一个示例:https://onlinegdb.com/KFqNSz2r6
我有一个 Action 类,它充当一些任意操作的容器。它的主要功能是充当状态机,以促进形成微控制器项目的非阻塞代码:
class Action {
public:
Action(int interval ,funcp_t callback ) : _interval(interval) , _callback(callback)
{
}
bool trigger(int now) {
if (now - _lastCheck > _interval) {
_lastCheck = now;
return true;
}
cout << "now: " << now;
cout << ", last: " << _lastCheck;
cout << ", interval: " << _interval;
cout << ", diff: " << (now - _lastCheck);
cout << endl;
return false;
}
void fire() {
cout << "action fired. last check: " << _lastCheck << endl;
_callback();
}
private:
int _interval = 0;
int _lastCheck = 0;
funcp_t _callback;
};
我还有一个 ActionManager 类,它充当动作的容器和编排器类。调用 tick 方法来推进所有动作的状态机:
class ActionManager {
public:
void addAction(Action action) {
_actions.push_back(action);
}
void tick() {
int now = millis();
for(auto action : _actions) {
if(action.trigger(now)) {
action.fire();
}
}
}
private:
vector<Action> _actions;
};
在我的其余设置代码中,我设置动作管理器,添加动作,然后启动一个无限循环(模拟 arduino 循环)以推进动作管理器的滴答声:
void sayHi() {
cout << "oh hi" << endl;
}
void sayHey() {
cout << "hey there" << endl;
}
ActionManager manager = ActionManager();
Action hiAction = Action(5000, sayHi);
Action heyAction = Action(1000, sayHey);
int main()
{
cout<<"--> Start <--" << endl;
manager.addAction(hiAction);
manager.addAction(heyAction);
while(true){
manager.tick();
cout << endl;
}
return 0;
}
我遇到的问题是 Action 实例的 _lastCheck 属性永远不会更新。控制台正在读取:
--> 开始
现在:65,最后:0,间隔:5000,差异:65
现在:65,最后:0,间隔:1000,差异:65
现在:86,最后:0,间隔:5000,差异:86
现在:86,最后:0,间隔:1000,差异:86
现在:98,最后:0,间隔:5000,差异:98
现在:98,最后:0,间隔:1000,差异:98
现在:107,最后:0,间隔:5000,差异:107
现在:107,最后:0,间隔:1000,差异:107
现在:118,最后:0,间隔:5000,差异:118
现在:118,最后:0,间隔:1000,差异:118
请注意,最后打印出来的校验值永远不会改变。
我很确定这个问题正在发生,因为当我调用 addAction 时,我的操作是按值而不是引用传递的,因此尝试将操作存储为指针向量:
class ActionManager {
public:
void addAction(Action *action) { // accept a pointer to an action
_actions.push_back(action);
}
void tick() {
int now = millis();
for(auto action : _actions) {
if(action->trigger(now)) {
action->fire();
}
}
}
private:
vector<Action *> _actions; // store a vector of actions
};
...
manager.addAction(&hiAction); // add by passing in the address of the action
manager.addAction(&heyAction);
但我仍然没有在上次检查中存储任何内容。
我觉得我错过了一些简单的东西,而且我已经解决这个问题太久了,看不到它。有什么想法吗?
【问题讨论】:
-
for(auto action : _actions)成为for(auto& action : _actions)。正如所写,action是来自_actions的元素的副本。然后_lastCheck在该临时副本中更新,并在原始副本中保持不变。 -
带指针的版本应该可以工作。我注意到您的在线示例使用了
500000和100000的间隔——即超过8 分钟和超过1 分钟。也许您只是等待的时间不够长。 -
"请注意,最后打印出来的校验值永远不会改变。" -- 为什么会改变?您显示的输出差异达到 118。在差异达到 1000(在您的示例中)之前,哪一行会为
_lastCheck分配一个新值? -
@IgorTandetnik 啊是的指针版本我只是不耐烦。时间不早了,我很沮丧。今天早上头脑清醒,查看回复,我发现它有效:) 感谢您的帮助!