3

すでに投稿されたコールバックをキャンセルするにはどうすればよいですか:

getIoService()->post(boost::bind(&MyClass::myCallback, this));

他の投稿されたコールバックはそのままにしておきますか?

問題は、別のスレッドからイベントを受け取るオブジェクトがあり、それらをメイン スレッドでイベントを処理するために ioservice にポストすることです。ある時点でオブジェクトを削除したい場合、ioservice は破棄されたオブジェクトで既にポストされたコールバックを実行しようとします。この場合、オブジェクトは削除されるため、オブジェクトにフラグを格納できません。

enable_shared_from_thisとを使用する解決策が考えられますがshared_from_this()、別の解決策があるかどうか疑問に思っています。

ありがとう

4

2 に答える 2

7

サムが答えたように、投稿されたハンドラーを選択的にキャンセルすることはできません。

有効期限が切れたオブジェクトでメンバー関数を呼び出さないようにすることが目標である場合、 usingenable_shared_from_thisが慣用的な解決策です。このアプローチの結果の 1 つは、オブジェクトの有効期間が少なくともハンドラーの有効期間まで延長されることです。オブジェクトのデストラクタを遅延できる場合は、 を介してオブジェクトをハンドラにバインドすることを検討してshared_from_this()ください。

一方、破棄を即時にする必要がある場合は、インスタンスに弱くバインドするファンクターを作成することを検討してください。 この質問では、へのバインドについて説明し、weak_ptrいくつかの研究/ディスカッション リンクを提供します。以下は、オブジェクトに弱くバインドするファンクターの単純化された完全な例です。

#include <iostream>
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/make_shared.hpp>
#include <boost/shared_ptr.hpp>

/// @brief Mocked up type.
class MyClass:
  public boost::enable_shared_from_this<MyClass>
{
public:
  MyClass()     { std::cout << "MyClass()"         << std::endl; }
  ~MyClass()    { std::cout << "~MyClass()"        << std::endl; }
  void action() { std::cout << "MyClass::action()" << std::endl; }
};

/// @brief weak_binder is a functor that binds a member function
///        to a weakly managed object instance.  I.e. this
///        functor will not extend the life of the instance to
///        which it has been bound.
template <typename Fn,
          typename C>
struct weak_binder
{
private:
  typedef typename C::element_type element_type;
public:

  /// @brief Constructor.
  weak_binder(Fn& fn, C& c) : fn_(fn), c_(c)
  {}

  /// @brief Conditional invoke Fn if C still exists.
  void operator()()
  {
    std::cout << "weak_binder::operator()" << std::endl;
    // Create a shared pointer from the weak pointer.  If
    // succesful, then the object is still alive.
    if (boost::shared_ptr<element_type> ptr = c_.lock())
    {
      // Invoke the function on the object.
      (*ptr.*fn_)();
    }
  }
private:
  Fn fn_;
  boost::weak_ptr<element_type> c_;
};

/// @brief Helper function to create a functor that weakly
///        binds to a shared object.
template <typename Fn,
          typename C>
weak_binder<Fn, C> weak_bind(Fn fn, C c)
{
  return weak_binder<Fn, C>(fn, c);
}

int main()
{
  boost::asio::io_service io_service;
  boost::shared_ptr<MyClass> my_class = boost::make_shared<MyClass>();

  // my_class will remain alive for this handler because a shared_ptr
  // is bound to handler B, and handler B will only be destroyed after
  // handler A has been destroyed.
  io_service.post(weak_bind(&MyClass::action,
                            my_class->shared_from_this())); // A

  // my_class will remain alive for this handler because it is bound
  // via a shared_ptr.
  io_service.post(boost::bind(&MyClass::action,
                              my_class->shared_from_this())); // B

  // my_class will not be alive for this handler, because B will have
  // been destroyed, and the my_class is reset before invoking the
  // io_service.
  io_service.post(weak_bind(&MyClass::action,
                            my_class->shared_from_this())); // C

  // Reset the shared_ptr, resulting in the only remaining shared_ptr
  // instance for my_class residing within handler B.
  my_class.reset();
  io_service.run();
}

そして結果の出力:

私のクラス()
weak_binder::operator()
MyClass::アクション()
MyClass::アクション()
〜マイクラス()
weak_binder::operator()

ご覧のとおり、MyClass::action()は 2 回だけ呼び出されます。1 回weak_binderはインスタンスが生きている間 (ハンドラー A)、もう 1 回boost::bindはインスタンスが維持されている間shared_ptr(ハンドラー B) です。ハンドラー C が呼び出されweak_binder::operator()ますが、インスタンスが破棄されたことを検出し、サイレント no-op が発生します。

于 2013-08-07T17:44:04.787 に答える