3

このことを考慮:

#include <boost/signals2.hpp>
#include <iostream>

struct object_with_slot
{
void operator()()
{
   std::cout << "Slot called!" << std::endl;
   member = 50500;
}
int member;
};


int main()
{
boost::signals2::signal<void ()> sig;

object_with_slot * ptr = new object_with_slot;
sig.connect(*ptr);

delete ptr;

sig();
}

出力は「Slot called!」です。クラッシュも何もありません。そのため、いくつか質問があります。

1) クラッシュしないのはなぜですか?

2) スロット関数が存在しないオブジェクトに何かを割り当ててもクラッシュしないのはなぜですか?

3) 信号がスロットの有効期間を自動的に追跡するようにするにはどうすればよいですか? つまり、スロットが破壊されると、切断されます。

質問番号 3 が最も重要です。オブザーバー パターンを実装する必要があり、オブザーバー (スロット) の有効期間が (アプリの実行中ずっと) 静的ではないことが非常に多いためです。

4

3 に答える 3

3

1) あなたはラッキーです。そうでない場合は、セグメンテーション違反が発生します。

2) メモリは決して上書きされませんでした。

3) slot::track を使用して、追跡対象のオブジェクトが削除されたときに自動的に切断することができます。Boost.Signals2 は、boost::shared_ptr によって管理されるオブジェクトを追跡できます。

#include <boost/signals2.hpp>
#include <boost/shared_ptr.hpp>

struct object_with_slot
{
    void operator()()
    {
       std::cout << "Slot called!" << std::endl;
       member = 50500;
    }
    int member;
};

//
int main()
{
    typedef boost::signals2::signal<void ()> sig_type;
    sig_type sig;

    {
        boost::shared_ptr<object_with_slot> ptr(new object_with_slot);
        sig.connect(sig_type::slot_type(*ptr).track(ptr));

        // 'object_with_slot' managed by ptr is destroyed
    }

    sig(); // 'object_with_slot' not called here.

    return 0;
}

更新:
std::shared_ptr および std::weak_ptr のオブジェクトを追跡するコードを追加しました:

#include <memory>
#include <boost/signals2.hpp>

// added specializations for std::weak_ptr and std::shared_ptr
namespace boost
{
  namespace signals2
  {
    template<typename T> struct weak_ptr_traits<std::weak_ptr<T> >
    {
      typedef std::shared_ptr<T> shared_type;
    };

    template<typename T> struct shared_ptr_traits<std::shared_ptr<T> >
    {
      typedef std::weak_ptr<T> weak_type;
    };
  }
}

struct object_with_slot
{
    void operator()()
    {
       std::cout << "Slot called!" << std::endl;
       member = 50500;
    }
    int member;
};

//
int main()
{
    typedef boost::signals2::signal<void ()> sig_type;
    sig_type sig;

    std::shared_ptr<object_with_slot> ptr(new object_with_slot);
    sig.connect(sig_type::slot_type(*ptr).track_foreign(ptr)); // ptr is tracked

    sig();

    return 0;
}
于 2013-02-14T20:20:19.410 に答える
1

1および2)実際、これは未定義の動作です。間接参照演算子を使用しました。これで、connectの値はobject_with_slotになり、そのアドレスはメモリマネージャーによって他のプロセスに自由に割り当てられます。偶然にも、それはまだ「有効なアドレス」です。また、ptrは、メモリリークを引き起こすことなく、他の値に自由に割り当てることができます。

このようなものを試してみると、毎回爆発することがわかります

#include <boost/signals2.hpp>
#include <iostream>

struct object_with_slot
{
    object_with_slot()
    {
        member = new int(10);
    }

    ~object_with_slot()
    {
        delete member; //comment this line and everything works again
    }
    void operator()()
    {
        std::cout << "Slot called!" << std::endl;
        *member = 50500; //it was destroyed above
    }
    int *member;
};


int main()
{
    boost::signals2::signal<void ()> sig;

    object_with_slot * ptr = new object_with_slot;
    sig.connect(*ptr);

    delete ptr;
    ptr = 0x0;

    sig();
}

3)object_with_slotのデストラクタに別のシグナルを設定し、呼び出されたときに通知することができます。

于 2013-02-14T20:15:09.167 に答える
0

非常に危険な例が示されています。見てみましょう:

#include <iostream>
#include <memory>
#include <boost/signals2.hpp>

struct object_with_slot
{
    object_with_slot() {
        std::cout << "ctor\n";
    }

    object_with_slot(const object_with_slot &) {
        std::cout << "cctor\n";
    }

    ~object_with_slot() {
        std::cout << "dtor\n";
    }

    void operator()()
    {
       std::cout << "Slot called!" << std::endl;
       member = 50500;
    }
    int member;
};

//
int main()
{
    typedef boost::signals2::signal<void ()> sig_type;
    sig_type sig;

    std::shared_ptr<object_with_slot> ptr(new object_with_slot);
    sig.connect(sig_type::slot_type(*ptr).track_foreign(ptr)); // ptr is tracked

    sig();

    return 0;
}

このコード (g++ 4.8.1、libboost 1.54) は何をしていると思いますか?

ctor
cctor
cctor
cctor
cctor
cctor
cctor
cctor
cctor
dtor
dtor
dtor
dtor
dtor
cctor
dtor
cctor
dtor
dtor
dtor
cctor
dtor
Slot called!
dtor
dtor

この動作が予期されていたとは思いません。*ptrメソッドに(インスタンスのobject_with_slot)のコピーを (値で) 渡すためconnectです。たとえば、参照ラッパーによって解決される場合があります。

sig.connect(sig_type::slot_type(boost::ref(*ptr)).track_foreign(ptr)); // ptr is tracked

テンプレートと型には注意してください。

于 2013-10-03T10:23:37.757 に答える