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.
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();
}