Demote Boost::Function to a Plain Function Pointer

demote boost::function to a plain function pointer

Has anyone noticed that the accepted answer only works with trivial cases? The only way that function<>::target() will return an object that can be bound to a C callback, is if it was constructed with an object that can be bound to a C callback. If that's the case, then you could have bound it directly and skipped all of the function<> nonsense to begin with.

If you think about it, there isn't any magic solution to this. A C-style callback is stored as a single pointer which points to executable code. Any nontrivial boost::function<> is going to need at least two pointers: one to the executable code, the other to the data that's needed to set up the call (e.g. the 'this' pointer, in the case of a bound member function).

The right way to use boost::function and boost::bind with C callbacks is to create a shim function that satisfies the callback signature, figures out which function<> to call, and calls it. Usually C callbacks will have some kind of a void* for 'user data'; that's where you stash your function pointer:

typedef void (*CallbackType)(int x, void* user_data);
void RegisterCallback(CallbackType cb, void* user_data);

void MyCallback(int x, void* userData) {
boost::function<void(int)> pfn = static_cast<boost::function<void(int)> >(userData);
pfn(x);
}

boost::function<void(int)> fn = boost::bind(myFunction(5));
RegisterCallback(MyCallback, &fn);

Of course, if your callback signature doesn't include some kind of user data pointer, you're out of luck. But any callback that doesn't include a user data pointer is already unusable in most real-world scenarios, and needs to be rewritten.

demote boost::function to a plain function pointer

Has anyone noticed that the accepted answer only works with trivial cases? The only way that function<>::target() will return an object that can be bound to a C callback, is if it was constructed with an object that can be bound to a C callback. If that's the case, then you could have bound it directly and skipped all of the function<> nonsense to begin with.

If you think about it, there isn't any magic solution to this. A C-style callback is stored as a single pointer which points to executable code. Any nontrivial boost::function<> is going to need at least two pointers: one to the executable code, the other to the data that's needed to set up the call (e.g. the 'this' pointer, in the case of a bound member function).

The right way to use boost::function and boost::bind with C callbacks is to create a shim function that satisfies the callback signature, figures out which function<> to call, and calls it. Usually C callbacks will have some kind of a void* for 'user data'; that's where you stash your function pointer:

typedef void (*CallbackType)(int x, void* user_data);
void RegisterCallback(CallbackType cb, void* user_data);

void MyCallback(int x, void* userData) {
boost::function<void(int)> pfn = static_cast<boost::function<void(int)> >(userData);
pfn(x);
}

boost::function<void(int)> fn = boost::bind(myFunction(5));
RegisterCallback(MyCallback, &fn);

Of course, if your callback signature doesn't include some kind of user data pointer, you're out of luck. But any callback that doesn't include a user data pointer is already unusable in most real-world scenarios, and needs to be rewritten.

boost::bind return a function object which is the argument for a function that requires pointer

Traditionally the final void * argument passed to callbacks is user defined data. If this is the case for you you can create a helper function that will let you pass functors. the only trouble is that you need to ensure that the user data exists until the callback will no longer be called - and that will depend a lot on your program structure. I'm just going to leak the object as thats the easiest way to ensure it continues to exist. ( Though you'll also have problems with the existance of the containing myC object ).

class myC
{
public:
myA *myOA;

//NOTE: I've removed the void* ptr here, which should be user data.
// If you still need it you'll need to bind it away at functor creation time.
int func(const char * poundVar , char * t1);

int myCCall()
{
//TODO: Fix this intentional leak.
boost::function<int(const char*, char*)> * fn = new boost::function<int(const char*,char*)>( boost::bind(&myC::func,this) );
//Call our helper function instead of `set_pound_func`.
set_pound_func_with_functor(myOA, fn );
return;
}
};

// Function that is really passed to `set_pound_func` when
// set_pound_func_with_functor is called.
// It converts the user data back to a boost function and calls it.
int pound_func_with_functor(const char* d1, char* d2, void* user_data)
{
boost::function<int(const char*,char*)> * fn = static_cast< boost::function<int(const char*, char*) >( user_data );
return (*fn)(d1,d2);
}

//Helper function to make set_pound_func work with boost functions instead.
//NOTE: You are required to ensure the fn argument exists for long enough...
void set_pound_func_with_functor( myA * myOA, boost::function<int(const char *, char *)> & fn )
{
myOA->bridge_set_pound_var_func( £_func_with_functor, &fn );
}

delete boost function while in use

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

No target() of boost::function of a member function

function::target() is defined (I'm using the C++11 draft, which I think is a bit more clear than boost's reference) as follows:

per C++0x n3290 20.8.11.2.5[func.wrap.func.targ]/3

Returns: If target_type() == typeid(T) a pointer to the stored function target; otherwise a null pointer.

In your case, T is your type void(*)(float), but Function.target_type() is not that at all, it is the type of the boost expression used to initialize boost::function.

So in short, yes, this is not allowed. The workarounds are not obvious, but here's one: demote boost::function to a plain function pointer

raw function pointer from a bound method

You can make your own class to do the same thing as the boost bind function. All the class has to do is accept the function type and a pointer to the object that contains the function. For example, this is a void return and void param delegate:

template<typename owner>
class VoidDelegate : public IDelegate
{
public:
VoidDelegate(void (owner::*aFunc)(void), owner* aOwner)
{
mFunction = aFunc;
mOwner = aOwner;
}
~VoidDelegate(void)
{}
void Invoke(void)
{
if(mFunction != 0)
{
(mOwner->*mFunction)();
}
}

private:
void (owner::*mFunction)(void);
owner* mOwner;
};

Usage:

class C
{
void CallMe(void)
{
std::cout << "called";
}
};
int main(int aArgc, char** aArgv)
{
C c;
VoidDelegate<C> delegate(&C::CallMe, &c);
delegate.Invoke();
}

Now, since VoidDelegate<C> is a type, having a collection of these might not be practical, because what if the list was to contain functions of class B too? It couldn't.

This is where polymorphism comes into play. You can create an interface IDelegate, which has a function Invoke:

class IDelegate
{
virtual ~IDelegate(void) { }
virtual void Invoke(void) = 0;
}

If VoidDelegate<T> implements IDelegate you could have a collection of IDelegates and therefore have callbacks to methods in different class types.



Related Topics



Leave a reply



Submit