Boost.Asio: Correct way to close socket and stop the timer and call the handler
===

suppose i have class X which encapsulates asio::ip::tcp::socket and deadline_timer. timer is used to break the connection if it is being too slow. Here is X:
    
    class X
    {
    public:
     typedef boost::function<void(const error_code&)> Handler;
     void f(Handler);
     void close();
    private:
     void on_connected(const error_code&);
     void on_timeout(const error_code&);
     void on_work_is_done(const error_code&);
     Handler h_;
     socket s_;
     deadline_timer t_;
    };

The function f does some work (send, receive, ...) and then calls handler like this:

    void on_work_is_done(const error_code& e)
    {
     //swapping handlers to release handler after function exits
     Handler h;
     h.swap(h_);
     h(e);
    }

During that time the timer t is ticking. So my problem is:
what is a good way to make X::close? close() must close socket s and stop timer t, and it seems very natural that it must call handler h but only after all async operations (on s and t) are cancelled. If there wasn't timer, then the problem is solved:

    void X::close() { s.close(); }
the async operations will be cancelled and on_work_is_done() will be called with err == operation_aborted, this will be passed to handler and then the handler will be released. Everything is ok. But since there are 2 objects and each of them might have some pending async operations, the problem appears to be more complex. Because if we do
    
    void X::close() 
    {
     s.close(); 
     t.cancel();
    }

both handlers (on_work_is_done, on_timeout) will be invoked, but we may call swapped handler_(err) from the handler that was invoked last. 
Is there some straightforward solution?

I see the following approaches: 

a) add size_t counter_ which will be set to 2 in X::close() and each of handlers will decrease it by 1. So the handler that made counter_ == 0 will invoke handler_(operation_aborted);

b) run t.cancel() and from on_timeout(err) if err == operation_aborted call s.cancel and from on_work_is_done() invoke handler_(operation_aborted)

Or the whole approach is bad and there is a better way?

