C ++中的函数钩子? [英] Function hooking in C++?

查看:173
本文介绍了C ++中的函数钩子?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

hooking我的意思是非侵入性地覆盖函数的行为的能力。一些示例:




  • 在函数体之前和/或之后打印日志消息。


  • 测量功能的持续时间

  • 等...

  • ul>

    我在各种编程语言和库中看到过不同的实现:




      <






    • Ruby method_missing

    • SWIG %exception 关键字,意味着将所有函数包装在try / catch块中,可以使用(ab) li>


    我的问题是:




    • 这样一个令人难以置信的有用的功能,我不知道为什么它从来没有实现为一个C ++语言功能。是否有任何理由阻止这种情况发生?

    • 在C ++程序中实现这些的一些推荐技术或库是什么?


    解决方案

    如果你说的是在函数体之前/之后调用一个新方法,而不改变函数体,你可以它在上使用自定义 shared_ptr 删除程序来触发后体函数。它不能用于 try / catch ,因为前后需要使用此技术的单独函数。



    另外,下面的版本使用 shared_ptr ,但是使用C ++ 11你应该能够使用 unique_ptr 相同的效果,而不需要每次使用时创建和销毁共享指针的成本。

      #include< iostream> 
    #include< boost / chrono / chrono.hpp>
    #include< boost / chrono / system_clocks.hpp>
    #include< boost / shared_ptr.hpp>

    template< typename T,typename Derived>
    class base_wrapper
    {
    protected:
    typedef T wrapped_type;

    Derived * self(){
    return static_cast< Derived *>(this);
    }

    wrapped_type * p;

    struct suffix_wrapper
    {
    Derived * d;
    suffix_wrapper(Derived * d):d(d){};
    void operator()(wrapped_type * p)
    {
    d-> suffix(p);
    }
    };
    public:
    explicit base_wrapper(wrapped_type * p):p(p){};


    void prefix(wrapped_type * p){
    //默认不做任何操作
    };

    void suffix(wrapped_type * p){
    //默认不做任何事情
    }

    boost :: shared_ptr< wrapped_type> operator->()
    {
    self() - > prefix(p);
    return boost :: shared_ptr< wrapped_type>(p,suffix_wrapper(self()));
    }
    };




    模板< typename T>
    class timing_wrapper:public base_wrapper< T,timing_wrapper< T> >
    {
    typedef base_wrapper< T,timing_wrapper< T> >基础;
    typedef boost :: chrono :: time_point< boost :: chrono :: system_clock,boost :: chrono :: duration< double> > time_point;

    time_point begin;
    public:
    timing_wrapper(T * p):base(p){}


    无效前缀(T * p)
    {
    begin = boost :: chrono :: system_clock :: now();
    }

    void suffix(T * p)
    {
    time_point end = boost :: chrono :: system_clock :: now

    std :: cout<< 时间:< (end-begin).count()< std :: endl;
    }
    };

    template< typename T>
    class logging_wrapper:public base_wrapper< T,logging_wrapper< T> >
    {
    typedef base_wrapper< T,logging_wrapper< T> >基础;
    public:
    logging_wrapper(T * p):base(p){}

    无效前缀(T * p)
    {
    std :: cout < 进入<< std :: endl;
    }

    void suffix(T * p)
    {
    std :: cout< 出口<< std :: endl;
    }

    };


    template< template< typename>类包装器,类型名T>
    wrapper< T> make_wrapper(T * p)
    {
    return wrapper< T>
    }


    class X
    {
    public:
    void f()const
    {
    sleep 1);
    }

    void g()const
    {
    std :: cout< __PRETTY_FUNCTION__<< std :: endl;
    }

    };



    int main(){

    X x1;


    make_wrapper< timing_wrapper>(& x1) - > f();

    make_wrapper< logging_wrapper>(& x1) - > g();
    return 0;
    }


    With "hooking" I mean the ability to non-intrusively override the behavior of a function. Some examples:

    • Print a log message before and/or after the function body.
    • Wrap the function body in a try catch body.
    • Measure duration of a function
    • etc...

    I have seen different implementations in various programming languages and libraries:

    • Aspect Oriented Programming
    • JavaScript's first class functions
    • OOP decorator pattern
    • WinAPI subclassing
    • Ruby's method_missing
    • SWIG's %exception keyword which is meant to wrap all functions in a try/catch block can be (ab)used for the purpose of hooking

    My questions are:

    • IMO this is such an incredibly useful feature that I wonder why it has never been implemented as a C++ language feature. Are there any reasons that prevent this from being made possible?
    • What are some recommended techniques or libraries to implement this in a C++ program?

    解决方案

    If you're talking about causing a new method to be called before/after a function body, without changing the function body, you can base it on this, which uses a custom shared_ptr deleter to trigger the after-body function. It cannot be used for try/catch, since the before and after need to be separate functions using this technique.

    Also, the version below uses shared_ptr, but with C++11 you should be able to use unique_ptr to get the same effect without the cost of creating and destroying a shared pointer every time you use it.

    #include <iostream>
    #include <boost/chrono/chrono.hpp>
    #include <boost/chrono/system_clocks.hpp>
    #include <boost/shared_ptr.hpp>
    
    template <typename T, typename Derived>
    class base_wrapper
    {
    protected:
      typedef T wrapped_type;
    
      Derived* self() {
        return static_cast<Derived*>(this);
      }
    
      wrapped_type* p;
    
      struct suffix_wrapper
      {
        Derived* d;
        suffix_wrapper(Derived* d): d(d) {};
        void operator()(wrapped_type* p)
        {
          d->suffix(p);
        }
      };
    public:
      explicit base_wrapper(wrapped_type* p) :  p(p) {};
    
    
      void prefix(wrapped_type* p) {
         // Default does nothing
      };
    
      void suffix(wrapped_type* p) {
         // Default does nothing
      }
    
      boost::shared_ptr<wrapped_type> operator->() 
      {
        self()->prefix(p);
        return boost::shared_ptr<wrapped_type>(p,suffix_wrapper(self()));
      }
    };
    
    
    
    
    template<typename T>
    class timing_wrapper : public base_wrapper< T, timing_wrapper<T> >
    {
      typedef  base_wrapper< T, timing_wrapper<T> > base;
      typedef boost::chrono::time_point<boost::chrono::system_clock, boost::chrono::duration<double> > time_point;
    
      time_point begin;
    public:
      timing_wrapper(T* p): base(p) {}
    
    
      void prefix(T* p) 
      {
        begin = boost::chrono::system_clock::now();
      }
    
      void suffix(T* p)
      {
        time_point end = boost::chrono::system_clock::now();
    
        std::cout << "Time: " << (end-begin).count() << std::endl;
      }
    };
    
    template <typename T>
    class logging_wrapper : public base_wrapper< T, logging_wrapper<T> >
    {
      typedef  base_wrapper< T, logging_wrapper<T> > base;
    public:
      logging_wrapper(T* p): base(p) {}
    
      void prefix(T* p) 
      {
        std::cout << "entering" << std::endl;
      }
    
      void suffix(T* p) 
      {
        std::cout << "exiting" << std::endl;
      }
    
    };
    
    
    template <template <typename> class wrapper, typename T> 
    wrapper<T> make_wrapper(T* p) 
    {
      return wrapper<T>(p);
    }
    
    
    class X 
    {
    public:
      void f()  const
      {
        sleep(1);
      }
    
      void g() const
      {
        std::cout << __PRETTY_FUNCTION__ << std::endl;
      }
    
    };
    
    
    
    int main () {
    
      X x1;
    
    
      make_wrapper<timing_wrapper>(&x1)->f();
    
      make_wrapper<logging_wrapper>(&x1)->g();
      return 0;
    }
    

    这篇关于C ++中的函数钩子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆