【问题标题】:Class instances not retaining data类实例不保留数据
【发布时间】: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&amp; action : _actions)。正如所写,action 是来自_actions 的元素的副本。然后 _lastCheck 在该临时副本中更新,并在原始副本中保持不变。
  • 带指针的版本应该可以工作。我注意到您的在线示例使用了500000100000 的间隔——即超过8 分钟和超过1 分钟。也许您只是等待的时间不够长。
  • "请注意,最后打印出来的校验值永远不会改变。" -- 为什么会改变?您显示的输出差异达到 118。在差异达到 1000(在您的示例中)之前,哪一行会为 _lastCheck 分配一个新值?
  • @IgorTandetnik 啊是的指针版本我只是不耐烦。时间不早了,我很沮丧。今天早上头脑清醒,查看回复,我发现它有效:) 感谢您的帮助!

标签: c++ pointers vector


【解决方案1】:

在您的原始版本中,问题在于当您迭代操作时,您会复制操作而不是引用它们。
for (auto action: _actions) 中,action 被复制。请改用for (auto&amp;&amp; action: _actions)

使用指针的版本没有这个问题,一旦now_lastCheck之间的差异大于_interval,就应该更新_lastCheck

【讨论】:

  • 太棒了。在您和@IgorTandetnik 的回复之间,我更新了代码并看到它有效。谢谢!一个后续问题,类型和变量名之间的&amp; 是什么意思?我知道 & 可以在变量前面表示“获取地址”,但在这种情况下似乎会有所不同 b/c 存储地址的变量只是一个指针。
  • &amp; 使action 成为参考;循环从for (Action action = ...) 变为for (Action&amp; action = ...),这当然会有所不同。考虑:int x = 1; int y = x; y = 2;x 仍然是 1)。 int&amp; z = x; z = 2;x 现在是 2)
  • 啊,好吧,这是有道理的。是的,我输入了这个问题并立即想到“我坐在电脑前,只需查找:P”并找到了一个很好的解释,说明了 c++ stackoverflow.com/a/8857890/1934903&amp; 的所有用法,这反映了您的回复。再次感谢!
  • 您可能还考虑到auto&amp;auto&amp;&amp; 之间存在差异。后一种也称为“通用引用”,它可以绑定到引用的范围并将值的生命周期延长到引用的范围,类似于 const 引用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-22
  • 2014-04-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-03
相关资源
最近更新 更多