28

C++ を学習し、いくつかのパターンに慣れようとしています。シグナル2 のドキュメントには、スロットとシグナルを使ってできることの膨大な配列が明確に記載されています。私が理解していないのは、どのタイプのアプリケーション (ユースケース) に使用する必要があるかということです。

私は、変更イベントをディスパッチするステート マシンに沿って考えています。動的に型付けされたバックグラウンド (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;
};
4

1 に答える 1

41

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

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

    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. 車輪を再発明することは、めったに良い考えではありません。

于 2013-09-08T07:07:14.047 に答える