Efficient method of passing callback member function

元气小坏坏 提交于 2021-02-07 18:03:20

问题


I'm designing a method for an input handler class. Here is some pseudo code...

void InputHandler::ScanEvents( boost::function1< void, std::string& > &func ) {
   // Scan keys, determining string to pass
     // If string found, call func with string as its argument on object tied to func
}

I'm not exactly sure how to implement this, or if it is even possible, since the whole point of a function is to separate it from its caller. The idea is that an object has a private member function and a boost::function member that holds it. Whenever it calls ScanEvents on its InputHandler, it passes that function, so the ScanEvents can "activate it" whenever an appropriate event is found.

Efficiency is a concern, as this is in a domain where performance is important, and this function is called frequently.

P.S. I swear I remember reading an example like this in one of Scott Meyer's books, but I can't find it for the life of me. Maybe it was in Modern C++ Design...looking....


回答1:


Something along the lines of

class Thingy
{
public:
    Thingy() : callback(bind(&Thingy::Callback, this, _1)) {}

    void DoStuff()
    {
        handler.ScanEvents(callback);
    }

private:
    InputHandler handler;
    function<void(string)> callback;

    void Callback(string s)
    {
        cout << "Called with " << s << endl;
    }
};

ought to do what you describe. But it would probably be more efficient for the callback to take the string by reference.




回答2:


boost::function has a reasonably slow overhead - about 20ns per call. I wouldn't call it from an inner loop - but neither would I call any other kind of function pointer. To invoke a member function, just use boost::lambda::bind to construct an anonymous wrapper function :

ih->ScanEvents(boost::lambda::bind(&ThisClass::CallbackFunc, this, boost::lambda::_1));

One option if you need really, really high performance would be to use an inlinable template function with a boost::lambda functor parameter:

template<typename F>
double democaller(const F &f) {
    double x = 1;
    for (int i = 0; i < 1000000; i++) {
        x = f(x);
    }
    return x;
}

namespace l = boost::lambda;

void demouser() {
    std::cout << democaller(l::_1 + 1);
}

On sufficiently high optimization settings, the lambda expression can be inlined into the calling site, eliminating overhead almost entirely.




回答3:


You might be looking for the command implementation in Modern C++ Design.

boost::function has just as much overhead as is necessary to do what it does. It's purpose is to allow you to pass around a "pointer" to any function that can respond to its interface. If you don't need this behavior then this overhead is real overhead. If you do then I honestly can't see a better approach than boost::function (it's even optimized to make sure you don't get a bunch of extra memory use from virtual functions in some implementations).

It is possible to construct a method that results in possibly inlined code but as soon as you try to store it in a generic interface you're going to get the boost::function overhead (maybe more).

What I would recommend is to just use boost::function until such time as you find you really need to replace it with something faster. THEN, and only then you write the template stuff of varying complexity to make it happen.

Simply storing the boost::function may be quite sufficient for what you're needing. You might also look at boost::signals.




回答4:


Usually, calling a private method on another class isn't the best idea.

You could implement an interface-style class and inherit that, and write your ScanEvents method to expect that type of input, eg:

class Notifyable {
  public:
    virtual void notify(std::string s) = 0;
};

void InputHandler::ScanEvents( Notifyable &n ) {
    // Scan keys, determining string to pass
      // If string found, call func with string as its argument on object tied to func
      n.notify(<string>);
}

I would think this might be faster too, just because you're avoiding any possible overhead with the boost::function wrapper.



来源:https://stackoverflow.com/questions/3098085/efficient-method-of-passing-callback-member-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!