I want the second timer to start working half a second after the second one, but the moment the second timer starts working, the terminal displays something completely different from what I want. If it does not impose restrictions before executing the second timer, then they both work as they should
#include <iostream>
#include <functional>
#include <boost/asio.hpp>
class print{
public:
print(boost::asio::io_context& io) : timer_(io, boost::asio::chrono::seconds(1)), count_(0){
timer_.async_wait(std::bind(&print::printer, this));
}
void printer(){
if(count_ < 5){
std::cout << count_ << "\n";
++count_;
timer_.expires_at(timer_.expiry() + boost::asio::chrono::seconds(1));
timer_.async_wait(std::bind(&print::printer, this));
}
}
~print(){
std::cout << "Last num " << count_ << "\n";
}
private:
boost::asio::steady_timer timer_;
int count_;
};
int main(){
boost::asio::io_context io;
print p(io);
boost::asio::steady_timer t(io, boost::asio::chrono::seconds(2));
t.async_wait([&io](const boost::system::error_code& ec){
if(!ec){
print pp(io);
}
});
io.run();
}
that's what the terminal outputs
0,
1,
Last num 0,
2,
3,
4,
Last num 5.
The second timer
ppis a local variable. It is destructed immediately.Therefore the async operation is using a deleted instance and invoked Undefined Behaviour.
You should probably be detecting cancellation by actually receiving
error_codein the completion handler. Thestd::bindexpression silently drops it for you, now.You can use dynamic allocation of some sort. I also strongly suggest separating and generalizing the notion of an interval timer and the action that is executed:
Now you can use it like:
See it Live On Coliru
Which prints:
Or more interactively: