Search code examples
c++boostc++11boost-bind

delete boost function while in use


I have a situation where a boost::function and boost::bind (actually a std::tr1::function and bind) are being deleted while still in use. Is this safe? I would normally avoid it, but the offending code is a bit entrenched and my only other option is adding a new thread.

typedef function<int(int)> foo_type;

foo_type* global_foo = NULL;

int actual_foo( int i, Magic* m )
{
    delete global_foo;
    return m->magic(i);
}

int main()
{
     Magic m;
    global_foo = new foo_type( bind( &actual_foo, _1, &m );

    return (*global_foo)(10)
}

The bound parameters are always plain integral types (an int and a pointer in the real code), and not references.


Solution

  • boost::function or std::tr1::functions are copyable objects. So, generally there is absolutly no reason to allocate them -- just pass them by value.

    They are well optimized for most of real cases... So just pass them by value:

    typedef function<int(int)> foo_type;
    
    foo_type global_foo;
    
    int actual_foo( int i, Magic* m )
    {
       delete global_foo;
       return m->magic(i);
    }
    
    int main()
    {
       Magic m;
       global_foo = bind( &actual_foo, _1, &m );
    
       return global_foo(10)
    }
    

    The code you suggested is dangerous, run this code:

        #include <boost/function.hpp>
        #include <boost/bind.hpp>
        #include <iostream>
        using namespace std;
    
        boost::function<void()> *glb;
    
        struct Data {
                int x;
                Data(int _x = 0) : x(_x) { cout<<"ctor:"<<this<<endl; }
                ~Data() { cout<<"dtor:"<<this<<endl; }
                Data(Data const &p) {x=p.x; cout<<"ctor:"<<this<<endl; }
                Data const &operator=(Data const &p) { x=p.x; cout<<this<<"="<<&p<<endl; return *this; }
        };
    
        void func(Data const &x)
        {
                delete glb;
                cout<<&x<<endl;
        }
    
        int main()
        {
                glb=new boost::function<void()>(boost::bind(func,Data(3)));
    
                (*glb)();
                return 0;
        }
    

    You would find that you try to access in func to destoryed object (dtor with same pointer value) that is shown in cout<<&x<<endl was already called.

    Because when you destroy your function objects you also destroy the binded parameters you have and Data const &x become unavailible becuase it was destoryed with global_function

    Edit: Clearification for comment:

    If you have something like

    map<string,function<void()> > calls;
    
    void delete_key(){
        calls.erase("key");
    }
    
    main() 
    {
         calls["key"]=delete_key;
    
         // Wrong and dangerous
         // You delete function while in use
         calls["key"]();
    
         // Correct and safe
         // You create a copy of function so it would not
         // be deleted while in use.
         function<void()> f=calls["key"];
         f();
    }