【问题标题】:c++ trigger function when bool changesc++ bool变化时触发函数
【发布时间】:2016-07-10 09:20:23
【问题描述】:

我有一个不断流式传输的布尔值。我需要在 bool 变为 true 时触发一个函数,在 bool 变为 false 时触发另一个函数,但每次更改只触发一次,所以我不能使用 while(true) 循环。

c++ 中“观察”一个值并在它发生变化时触发的最佳方式是什么?

谢谢。

【问题讨论】:

标签: c++ boolean-logic


【解决方案1】:

我会通过设置一个 flagTrue 变量和一个 flagFalse 变量来解决这个问题。当您遇到第一个 True 时,flagTrue 会从 false 更改为 true,并且所有后续 True 布尔值都将被忽略。同样,当您遇到 firat False 时,flagFalse 将从 False 更改为 True 并忽略所有后续 False 布尔值。此外,当被检查的布尔值从 True 更改为 False 时,您将 flagTrue 更改为 False,在另一种情况下类似。
示例:

flagTrue = false
flagFalse = false
if (bool == true && flagTrue == false)
{
   // DoSomething
   flagTrue = true;
   flagFalse = false;
}
else if (bool == false && flagFalse == false)
{
   // DoSomething
   flagTrue = false;
   flagFalse = true;
}

【讨论】:

  • 谢谢! (已编辑)所以相反的是:if (bool == false&& flagFalse == False) { // DoSomething flagTrue = False; flagFalse = True; } 对吗?
  • 我已经添加了初始化。我相信他们更清楚地说明了这一点。是的,您添加的相反是正确的。我已经更新了我的代码。请检查一下。
  • 啊,我明白了。完全有道理。再次感谢您!
  • 你不需要两个标志,一个就足够了:static bool isActive = false; bool newVal = read(); if(newVal != isActive) { isActive = newVal; /* callback depending on isActive */ }
  • std::atomic::exchange 为您提供以前的状态信息,同时在多线程环境中是安全的。
【解决方案2】:

我可能会这样开始:

#include <functional>
#include <atomic>
#include <iostream>

struct trigger
{
  using closure_type = std::function<void()>;

  trigger(closure_type on_set, closure_type on_reset, bool initial_state = false)
  : _state { initial_state }
  , _on_set(std::move(on_set))
  , _on_reset(std::move(on_reset))
  {}

  void set() {
    if (not _state.exchange(true)) {
      _on_set();
    }
  }

  void reset() {
    if (_state.exchange(false)) {
      _on_reset();
    }
  }

  std::atomic<bool> _state;
  std::function<void()> _on_set;
  std::function<void()> _on_reset;
};

void has_set() {
  // you can marshall accross threads here by posting calls to a 
  // queue
  std::cout << __func__ << std::endl;
}

void has_unset() {
  // you can marshall accross threads here by posting calls to a 
  // queue
  std::cout << __func__ << std::endl;
}

int main()
{
  trigger t { has_set, has_unset };

  t.set();
  t.set();

  t.reset();
  t.reset();

}

【讨论】:

    【解决方案3】:

    看看观察者模式。你可以将你的布尔值包装在一个帮助类中,只要设置了布尔值就会触发一个事件。

    observable bool 的示例实现:

    #include <vector>
    
    class Observer {
    public:
        virtual void valueChanged() = 0;
    };
    
    class ObservableBool {
    private:
        bool value;
        std::vector<Observer*> observers = std::vector<Observer*>();
    
    public:
        bool getValue() {
            return value;
        }
    
        bool setValue(bool value) {
            bool changed = (value != this->value);
            this->value = value;
            if(changed) raiseEvent();
        }
    
        void addObserver(Observer* observer) {
            observers.push_back(observer);
        }
    
        void removeObserver(Observer* observer) {
            observers.erase(std::find(observers.begin, observers.end, observer));
        }
    
    private:
        void raiseEvent() {
            for (int i = 0; i < observers.size; ++i) {
                observers[i]->valueChanged();
            }
        }
    };
    

    这可以改进很多。一个非常好的方法是实现从和到 bool 的隐式转换(但要小心,为 bool 重载 '=' 运算符可能很危险)。您可以将其模板化以支持任意类型而不仅仅是 bool,您应该使用智能指针而不是原始指针(std::weak_ptr 最好),而不是 Observer 类,您可能应该使用函数指针来正确支持 lambda。如果你做得对,你可以像使用普通布尔值一样使用类,设置新值时开销很小。默认情况下,对更改的所有反应都由更改值的线程执行。

    【讨论】:

      【解决方案4】:

      聚会有点晚了,但如果你只是想把它搞砸(比如测试),这里有一个稍微简单的解决方案:

      /**
       * @brief Set a boolean variable.
       * @param b Pointer to the boolean variable.
       * @param value Set to this value.
       * @return Returns if the value was to be changed.
       */
      bool set(bool* b, bool value)
      {
          // if b isn't going to change
          if (*b == value) return false;
      
          // if b is going to change
          else
          {
              *b = value;
              return true;
          }
      }
      
      /**
       * @brief A possible implementation
       */
      int main()
      {
          bool my_variable = false;
      
          while(true)
          {
              // Set my_variable and flag it if it changed
              bool changed = set(&my_variable, some_function());
      
              // check for changed
              if (changed)
              {
                  // ...
              }
          }
      }
      

      这似乎比实现布尔包装类、触发器和观察者模式要少一些。

      【讨论】:

        猜你喜欢
        • 2021-08-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-11-28
        • 1970-01-01
        • 2021-02-27
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多