c ++保存绑定对象并在asio之后使用它

c++ saving bound object and using it after asio

我正在尝试将绑定的结果保存到 std:function,然后将其作为参数传递给另一个函数,并将其存储为数据成员。然后我使用 asio async_wait,但是当我从等待中 return 尝试操作我保存的函数时,我得到了分段错误。知道为什么吗?

#include <memory>
#include <iostream>
#include <asio/io_service.hpp>
#include <functional>
#include <asio/deadline_timer.hpp>

using namespace std;

typedef std::function<void (const std::error_code& error)> TM_callback;

class Timer {
public:
    Timer(asio::io_service& io_service) :_timer(io_service) {}

    void start(TM_callback cb) {
        _cb = cb;
      _timer.expires_from_now(boost::posix_time::milliseconds(1000));
        TM_callback timeoutFunc = std::bind(&Timer::onTimeout, this, std::placeholders::_1);
        _timer.async_wait(timeoutFunc);
    }

private:
    void onTimeout(const std::error_code& error) {
        (_cb)(error); // <-- here i get segmentation fault
    }

    TM_callback _cb;
    asio::deadline_timer _timer;
};

class COL {
public:
    COL(asio::io_service& io_service): _inTimer(io_service){}
void startInTimer() {
    TM_callback cb = std::bind(&COL::onInTimeout, this, std::placeholders::_1);
    _inTimer.start(cb);
}

private:
void onInTimeout(const std::error_code& error) {cout<<error.message();}
    Timer _inTimer;
};

int main()
{
    asio::io_service io_service;
    COL col(io_service);
    col.startInTimer();

    return 0;
}

好的,最有可能的问题出在您没有显示的代码中。如你所见@m.s。 "imagine" 不是你的问题。他也忘记了 io_service::run():

int main() {
    asio::io_service io_service;
    COL col(io_service);
    col.startInTimer();
    io_service.run();
}

还是没问题。 Live On Coliru

inTimer 不能保证在执行完成处理程序之前存在时,问题就开始了:

int main() {
    asio::io_service io_service;
    {
        COL col(io_service);
        col.startInTimer();
    }
    io_service.run();
}

现在你有 Undefined Behaviour: Live On Coliru

解决方案

最简单的解决方案是使 COL 是什么?)对象足够长的时间。更多 structural/idiomatic 的方法是让 bind 保持 Timer 对象存活,例如使用 shared_ptr:

Live On Coliru

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

using namespace std;

typedef std::function<void(const boost::system::error_code &error)> TM_callback;

namespace asio = boost::asio;

class Timer : public boost::enable_shared_from_this<Timer> {
  public:
    Timer(asio::io_service &io_service) : _timer(io_service) {}

    void start(TM_callback cb) {
        _cb = cb;
        _timer.expires_from_now(boost::posix_time::milliseconds(1000));
        TM_callback timeoutFunc = boost::bind(&Timer::onTimeout, shared_from_this(), boost::asio::placeholders::error);
        _timer.async_wait(timeoutFunc);
    }

  private:
    void onTimeout(const boost::system::error_code &error) {
        (_cb)(error);
    }

    TM_callback _cb;
    asio::deadline_timer _timer;
};

class COL : public boost::enable_shared_from_this<COL> {
  public:
    COL(asio::io_service &io_service) : _svc(io_service) {}

    void startInTimer() {
        TM_callback cb = boost::bind(&COL::onInTimeout, shared_from_this(), boost::asio::placeholders::error);

        boost::shared_ptr<Timer> _inTimer = boost::make_shared<Timer>(_svc);
        _inTimer->start(cb);
    }

  private:
    void onInTimeout(const boost::system::error_code &error) { cout << error.message(); }
    asio::io_service& _svc;
};

int main() {
    asio::io_service io_service;
    {
        boost::make_shared<COL>(io_service)->startInTimer();
    }
    io_service.run();
}

请注意,这也巧妙地解决了在给定时间不能有多个计时器处于飞行状态的问题(安排新计时器会取消挂起的计时器)。