【问题标题】:Implementing signals (Observer pattern): is mutable or const_cast necessary?实现信号(观察者模式):需要 mutable 还是 const_cast?
【发布时间】:2016-08-27 15:00:32
【问题描述】:

我正在实现我自己的signal/slot(观察者模式,Qt 风格)机制,所以我可以有一个property 来通知......东西......它已经改变了。

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

  1. const_castconnect 中的列表。
  2. 列出mutable。

在我看来,两者都是一样的(这在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;

};

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

【问题讨论】:

  • 未经测试的代码... tsk tsk...
  • @Arnav 我现在正在编写测试,我只需要解决这个设计问题:p。
  • 恐怕我不明白为什么signal 本身应该暴露const 方法。为什么不让signal 的用户决定他们是否希望它是可变的(或不可变的)?
  • @MatthieM。将信号想象为对象的成员。如果该对象在特定上下文中是 const ,则不能简单地连接到其信号,这需要用户代码放弃一定程度的 const 正确性。我不清楚,我可以尝试提供一个代码示例来说明我的意思。

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


【解决方案1】:

mutable 通常是此类情况的更好选择。

尽可能避免 (const) 强制转换,它很容易出现未定义的行为,而 mutable 保证不会1)。


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

【讨论】:

    【解决方案2】:

    有两种直接的方法可以解决这个问题:

    1. const_castconnect 中的列表。
    2. 列出mutable。

    实际上还有第三种选择(这是一个通用的解决方法,如果 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 函数的线程安全时,了解这一点是很好的。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多