正如Sam回答的那樣,不可能有選擇地取消發佈的處理程序。
如果目標是防止對其生命週期已過期的對象調用成員函數,那麼使用enable_shared_from_this
是慣用的解決方案。這種方法的一個結果是對象的生命週期至少延長到處理程序的壽命。如果對象的析構函數可以被延遲,那麼考慮通過shared_from_this()
將對象綁定到處理程序。另一方面,如果需要立即銷燬,那麼可以考慮編寫一個與實例弱結合的函子。 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();
}
並且得到的輸出:
MyClass()
weak_binder::operator()
MyClass::action()
MyClass::action()
~MyClass()
weak_binder::operator()
如可以觀察到,MyClass::action()
僅調用兩次:一次通過weak_binder
而實例處於活動狀態(處理程序A),並且一旦通過boost::bind
,實例通過shared_ptr
(處理程序B)進行維護。處理程序C被調用,但weak_binder::operator()
檢測到實例已被銷燬,導致無聲操作。
好吧,我看,那麼如何刪除所有回調? – Artem
問題是我有一些對象接收來自不同線程的事件,並將它們發佈到ioservice以處理主線程中的事件。如果在某些時候我想刪除我的對象 - ioservice會嘗試在已銷燬的對象中執行已發佈的回調。在這種情況下,我不能在對象中存儲任何標誌,因爲它將被刪除。 – Artem
@Artem請用這個新信息編輯你的問題,你沒有提到你的原始問題中的線程或刪除對象。 –