实现信号(Observer模式):是必需的还是const_cast?

时间:2016-08-27 15:00:32

标签: c++ c++11 observer-pattern signals-slots

我正在实现我自己的signal / slot(观察者模式,Qt样式)机制,所以我可以有一个property来通知......那些已经改变了。< / p>

我认为C ++ 11提供了所有必要的功能,可以实现非常简洁和功能强大的实现。我遇到的“问题”是,如果我想“连接”到const对象的信号,我需要signal::connect函数为const,但修改回调列表/观察者。有两种直接解决方法:

  1. const_cast connect内的列表。
  2. 制作列表mutable
  3. 在我看来,这两件事情都是一样的(之前已经问过,例如。{/ em>在this question中),并且在逻辑上非常精细,但风格上有问题。因此问题。有没有办法解决这个问题,或者这是对const_cast / mutable的真正合理使用吗?

    我现在拥有的一些预备代码:

    template<typename... ArgTypes>
    class signal
    {
    public:
      template<typename Callable>
      void connect(Callable&& callback) const
      {
        std::lock_guard<std::mutex> lock(slots_mutex);
        slots.emplace_back(callback);
      }
    
      void emit(ArgTypes... arguments) const
      {
        std::lock_guard<std::mutex> lock(slots_mutex);
        for(auto&& callback : slots)
        {
          callback(arguments...);
        }
      }
    
    private:
      // mutable here allows to connect to a const object's signals
      mutable std::vector<std::function<void(ArgTypes...)>> slots;
      std::mutex slots_mutex;
    
    };
    

    注意我没有测试过这段代码;这只是我当前心态的反映。

3 个答案:

答案 0 :(得分:9)

对于此类案件,

mutable通常是更好的选择。

尽可能避免(const)投射,它很容易遇到未定义的行为,而mutable保证不是 1)

1 mutable类成员保证不会转到例如.text段的发射代码。

答案 1 :(得分:2)

  

有两种直接解决方法:

     
      
  1. const_cast connect内的列表。
  2.   
  3. 制作列表mutable
  4.   

实际上还有第三种选择(这是一种通用的可能解决方法,如果C ++没有提供mutable关键字) - 您可以将相关数据移出语法对象:

class X
{
    mutable int           i1_;

    // Data pointed to by i2_ semantically belongs to this object
    // but doesn't constitute a syntactical part of it so it is not
    // subject to const-correctness checks by the compiler.
    std::unique_ptr<int>  i2_;

public:
    void constFunc() const {
        i1_  = 123;
        *i2_ = 456;
    }
};

尽管有这个额外选项,我仍然同意πάντα ῥεῖ answer mutable关键字是这种情况的正确选择。它以标准化的方式(例如允许被grepped)明确地记录该类的概念const操作在技术上可能不是非变异的。例如,当关注类的const函数的线程安全时,这很有用。

答案 2 :(得分:0)

signal :: connect 会修改 signal :: slot 。所以,我认为你唯一需要做的就是改变你的设计。让 signal :: connect 变为可变,并且调用者持有可变信号指针。