Alex Rivera | Logout

How to write an anonymous function / lambda that passes itself as a callback?

Asked 2011-12-14T05:27:09.517
8

I am learning boost::asio and C++11 simultaneously. One of my test programs, which is actually an adaptation of one of the samples given in the boost::asio tutorial is the following:

#include <iostream>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>

class printer {

// Static data members
private:
    const static boost::posix_time::seconds one_second;

// Instance data members
private:
    boost::asio::deadline_timer timer;
    int count;

// Public members
public:
    printer(boost::asio::io_service& io)
        : timer(io, one_second), count(0) {

        std::function<void(const boost::system::error_code&)> callback;
        callback = [&](const boost::system::error_code&) { // critical line
            if (count < 5) {
                std::cout << "Current count is " << count++ << std::endl;

                timer.expires_at(timer.expires_at() + one_second);
                timer.async_wait(callback);
            }
        };

        timer.async_wait(callback);
    }

    ~printer() {
        std::cout << "Final count is " << count << std::endl;
    }
};

const boost::posix_time::seconds printer::one_second(1);

int main() {
    boost::asio::io_service io;
    printer p(io);
    io.run();

    return 0;
}

When I run this program, I get a segmentation fault. I do understand why I get the segmentation fault. After the constructor is done running, the constructor's callback variable goes out of scope, and the lambda's callback variable, which is a reference to the constructor's callback variable, becomes a dangling reference.

So I modify the critical line with:

        callback = [callback, &](const boost::system::error_code&) { // critical line
<
Edit
Report

1 Answer

4

To learn about Asio and C++11 I recommend the boostcon talk "Why C++0x is the Awesomest Language for Network Programming" by the designer of asio himself. (Christopher Kohlhoff)

https://blip.tv/boostcon/why-c-0x-is-the-awesomest-language-for-network-programming-5368225 http://github.com/chriskohlhoff/awesome

In this talk, C.K takes a typical small asio application and start to add C++11 feature one by one. There is a part about lambda around the middle of the talk. The kind of issue you have with life-time of lambda is workaround by using the following pattern :

#include <iostream>
#include <boost/asio.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <memory>

class printer 
{

// Static data members
private:
    const static boost::posix_time::seconds one_second;

// Instance data members
private:
    boost::asio::deadline_timer timer;
    int count;

// Public members
public:
    printer(boost::asio::io_service& io)
        : timer(io, one_second), count(0) {
       wait();
    }

    void wait() {
        timer.async_wait(
            [&](const boost::system::error_code& ec) {
               if (!ec && count < 5) {
                 std::cout << "Current count is " << count++ << std::endl;

                 timer.expires_at(timer.expires_at() + one_second);
                 wait();
               }
            });
    }

    ~printer() {
        std::cout << "Final count is " << count << std::endl;
    }
};

const boost::posix_time::seconds printer::one_second(1);

int main() {
    boost::asio::io_service io;
    printer p(io);
    io.run();

    return 0;
}
answered 2011-12-15T19:13:45.000

Your Answer