web-dev-qa-db-ja.com

ブーストシグナルを使用する方法と理由2?

C++を学び、いくつかのパターンに慣れようとしています。 signals2 doc には、スロットとシグナルを使用して実行できるさまざまなことが明らかにあります。私が理解していないのは、どのタイプのアプリケーション(ユースケース)に使用すべきかということです。

変更イベントをディスパッチするステートマシンの方針に沿って考えています。動的に型指定されたバックグラウンド(C#、Javaなど)から来る場合は、イベントディスパッチャーまたは静的参照またはコールバックを使用します。

クラス間コールバックの使用に関してC++に問題はありますか?それは本質的になぜsignals2が存在するのですか?

例の1つは、ドキュメント/ビューです。このパターンは、関数のベクトルを使用してループ内でそれぞれを呼び出す、または登録されたリスニングクラスインスタンスの状態変化を呼び出すラムダを言うよりも、どのように適していますか?

class Document
{
public:
    typedef boost::signals2::signal<void ()>  signal_t;

public:
    Document()
    {}

    /* Connect a slot to the signal which will be emitted whenever
      text is appended to the document. */
    boost::signals2::connection connect(const signal_t::slot_type &subscriber)
    {
        return m_sig.connect(subscriber);
    }

    void append(const char* s)
    {
        m_text += s;
        m_sig();
    }

    const std::string& getText() const
    {
        return m_text;
    }

private:
    signal_t    m_sig;
    std::string m_text;
};

そして

class TextView
{
public:
    TextView(Document& doc): m_document(doc)
    {
        m_connection = m_document.connect(boost::bind(&TextView::refresh, this));
    }

    ~TextView()
    {
        m_connection.disconnect();
    }

    void refresh() const
    {
        std::cout << "TextView: " << m_document.getText() << std::endl;
    }
private:
    Document&               m_document;
    boost::signals2::connection  m_connection;
};
20
FlavorScape

Boost.Signals2は単なる「コールバックの配列」ではなく、多くの付加価値があります。 IMO、最も重要なポイントは次のとおりです。

  1. スレッドセーフ:競合状態を発生させることなく、複数のスレッドが同じ信号を同時に接続/切断/呼び出すことができます。これは、独自のスレッドで実行されているアクティブオブジェクトなどの非同期サブシステムと通信する場合に特に便利です。
  2. connectionおよびscoped_connectionハンドルは、signalに直接アクセスせずに切断できるようにします。これが、boost::function(またはstd::function)のような比類のないスロットを切断する唯一の方法であることに注意してください。
  3. 一時的なスロットブロッキング。リスニングモジュールを一時的に無効にするクリーンな方法を提供します(たとえば、ユーザーがビューでのメッセージの受信を一時停止するように要求した場合)。
  4. 自動スロット寿命追跡:信号は「期限切れ」スロットから自動的に切断されます。スロットがshared_ptrsによって管理されているコピー不可能なオブジェクトを参照するバインダーである場合の状況を考えてみましょう。

    shared_ptr<listener> l = listener::create();
    auto slot = bind(&listener::listen, l.get()); // we don't want aSignal_ to affect `listener` lifespan
    aSignal_.connect(your_signal_type::slot_type(slot).track(l)); // but do want to disconnect automatically when it gets destroyed
    

確かに、「関数のベクトルを使用し、ループ内でそれぞれを呼び出す」など、上記のすべての機能を自分で再実装できますが、問題は、Boost.Signals2よりも優れているかどうかです。車輪の再発明が良い考えになることはめったにありません。

25
Igor R.