3

我需要将一个方法绑定到一个函数回调中,除了这个片段不合法,如demote-boostfunction-to-a-plain-function-pointer中讨论的那样。

获得这种行为的最简单方法是什么?

struct C {
void m(int x) {
    (void) x;
    _asm int 3;
}};

typedef void (*cb_t)(int);
int main() {
    C c;
    boost::function<void (int x)> cb = boost::bind(&C::m, &c, _1);
    cb_t raw_cb = *cb.target<cb_t>(); //null dereference
    raw_cb(1);
    return 0;
}
4

4 回答 4

2

您可以将该绑定参数推入全局变量并创建一个静态函数,该函数可以获取该值并在其上调用该函数,或者您将不得不动态生成每个实例的函数 - 这将涉及一些一种即时代码生成在堆上生成一个存根函数,该函数将静态局部变量设置为您想要的值,然后在其上调用该函数。

第一种方法简单易懂,但根本不是线程安全的或可重入的。第二个版本是混乱和困难的,但如果做得好,它是线程安全的和可重入的。

编辑:我刚刚发现 ATL 使用代码生成技术来做到这一点 - 它们动态生成设置this指针和其他数据的 thunk,然后跳转到回调函数。 这是一篇 CodeProject 文章,它解释了它是如何工作的,并可能让您了解如何自己做。特别注意最后一个示例(程序 77)。

请注意,自从撰写本文以来,DEP 已经存在,您需要使用VirtualAllocwithPAGE_EXECUTE_READWRITE来获取一块内存,您可以在其中分配您的 thunk 并执行它们。

于 2009-02-05T15:49:06.573 回答
2

你可以让你自己的类做和 boost 绑定函数一样的事情。该类所要做的就是接受函数类型和指向包含该函数的对象的指针。例如,这是一个 void return 和 void param 委托:

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

用法:

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

现在,既然VoidDelegate<C>是一个类型,拥有这些的集合可能是不切实际的,因为如果列表也包含 B 类的函数怎么办?它不能。

这就是多态性发挥作用的地方。你可以创建一个接口 IDelegate,它有一个函数 Invoke:

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

如果VoidDelegate<T>实现 IDelegate,您可以拥有 IDelegate 的集合,因此可以对不同类类型中的方法进行回调。

于 2009-02-05T16:02:14.957 回答
1
#include <iostream>
typedef void(*callback_t)(int);

template< typename Class, void (Class::*Method_Pointer)(void) >
void wrapper( int class_pointer )
{
   Class * const self = (Class*)(void*)class_pointer;
   (self->*Method_Pointer)();
}

class A
{
public:
   int m_i;
   void callback( )
   { std::cout << "callback: " << m_i << std::endl; }
};

int main()
{
   A a = { 10 };
   callback_t cb = &wrapper<A,&A::callback>;
   cb( (int)(void*)&a);
}
于 2010-01-27T17:31:59.027 回答
0

我现在可以通过将 C 转换为单例,将 C::m 分解为 C::m_Impl 并声明静态 C::m(int) 来将其转发到单例实例。谈论一个黑客。

于 2009-02-05T15:54:27.577 回答