首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在每个函数的入口处添加代码?

如何在每个函数的入口处添加代码?
EN

Stack Overflow用户
提问于 2011-02-23 00:45:32
回答 6查看 6.3K关注 0票数 16

我想在每次函数调用之前添加一些代码来做一些检查。我知道的唯一方法是:

代码语言:javascript
运行
复制
#define SOME_CODE printf("doing something...");

class testObject
{
void function1()
{
 SOME_CODE
 ...
}
void function2()
{
 SOME_CODE
 ...
}
}

有没有更干净的方法来实现这一点?我正在寻找一种方法,这样我就不需要手动为每个函数添加"SOME_CODE“。

EN

回答 6

Stack Overflow用户

回答已采纳

发布于 2011-02-23 01:00:10

根据您希望实现的结果,您可以使用包装实际调用的函数器对象在C++中创建一些东西(对于自由函数或静态成员函数来说很容易),例如:

代码语言:javascript
运行
复制
#include <iostream>

template<void f(void)>
struct Wrap {
   void operator()() const {
      std::cout << "Pre call hook" << std::endl;
      f();
   }
};

namespace {
   void test_func() {
      std::cout << "Real function" << std::endl;
   }
}

const Wrap<&test_func> wrapped_test_func = {};

int main() {
   wrapped_test_func();
   return 0;
}

显然,这需要做更多的工作才能足够通用,例如C++0x可变模板或大量重载。让它与成员函数很好地协同工作也更加繁琐。

我也为成员函数勾勒出了一种(非侵入式的)方式:

代码语言:javascript
运行
复制
#include <iostream>

template<class C, void (C::*F)()>
class WrapMem {
   C& inst;
public:
   WrapMem(C& inst) : inst(inst) {}

   void operator()() {
      std::cout << "Pre (method) call hook" << std::endl;
      ((inst).*(F))();
   }

   void operator()() const {
      std::cout << "Pre (method, const) call hook" << std::endl;
      ((inst).*(F))();
   }
};

class Foo {
public:
   void method() { std::cout << "Method called" << std::endl; }
   void otherstuff() {}
};

class FooWrapped : private Foo  {
public:
   FooWrapped() : method(*this) {}
   using Foo::otherstuff;
   WrapMem<Foo,&Foo::method> method;
};

int main() {
   FooWrapped f;
   f.otherstuff();
   f.method();
   return 0;
}

您也可以跳过私有继承和using来公开非包装方法,但是您需要小心析构函数,如果这样做,很容易被意外绕过。(例如,隐式强制转换以引用基类)。非侵入式方式也仅限于公共接口,也不能用于内部调用。

使用C++11,您可以获得完美的转发,还可以将包装对象的构造简化为一个简单的宏,该宏获取类和成员函数名并为您推导出其余部分,例如:

代码语言:javascript
运行
复制
#include <iostream>
#include <utility>

template <typename Ret, typename ...Args>
struct Wrapper {
  template <class C, Ret (C::*F)(Args...)> 
  class MemberFn {
    C& inst;
  public:
    MemberFn(C& inst) : inst(inst) {}
    MemberFn& operator=(const MemberFn&) = delete;

    Ret operator()(Args&& ...args) {
      return ((inst).*(F))(std::forward<Args>(args)...);
    }

    Ret operator()(Args&& ...args) const {
      return ((inst).*(F))(std::forward<Args>(args)...);
    }
  };
};

template <typename T>
struct deduce_memfn;
template <typename C, typename R, typename... Args>
struct deduce_memfn<R (C::*)(Args...)> {
  template <R(C::*F)(Args...)> 
  static typename Wrapper<R, Args...>::template MemberFn<C, F> make();
};

template <typename T>
decltype(deduce_memfn<T>()) deduce(T);

template <typename T>
struct workaround : T {}; // Clang 3.0 doesn't let me write decltype(deduce(&Class::Method))::make...

#define WRAP_MEMBER_FN(Class, Method) decltype(workaround<decltype(deduce(&Class::Method))>::make<&Class::Method>()) Method = *this

class Foo {
public:
  Foo(int);
  double method(int& v) { return -(v -= 100) * 10.2; }
  void otherstuff();
};

class WrappedFoo : private Foo {
public:
  using Foo::Foo; // Delegate the constructor (C++11)
  WRAP_MEMBER_FN(Foo, method);
  using Foo::otherstuff;
};

int main() {
  WrappedFoo f(0);
  int i = 101;
  std::cout << f.method(i) << "\n";
  std::cout << i << "\n";
}

(注意:这个推论不适用于重载)这是用Clang 3.0测试的。

票数 6
EN

Stack Overflow用户

发布于 2011-02-23 01:10:23

对于gcc来说,对于MSVC也有一个类似的解决方案,其他人发布了一个答案:

代码语言:javascript
运行
复制
#include <iostream>
int depth=-1;
extern "C" {
    void __cyg_profile_func_enter (void *, void *) __attribute__((no_instrument_function));
    void __cyg_profile_func_exit (void *, void *) __attribute__((no_instrument_function));
    void __cyg_profile_func_enter (void *func,  void *caller)
    {
        depth++;
    }


    void __cyg_profile_func_exit (void *func, void *caller)
    {
        depth--;
    }
}

class Foo {
public:
    void bar() {
        std::cout << "bar: " << depth << std::endl;
    }
};

int main() {
    Foo f;
    f.bar();
    return 0;
}

使用g++ -Wall -Wextra -finstrument-functions编译。但是要注意,不要从工具钩子中调用插入指令的函数!(有关排除事物的方法,请参阅手册页)

票数 13
EN

Stack Overflow用户

发布于 2011-02-23 00:49:43

这取决于您使用的编译器。我使用的是DevStudio 2005,在联机帮助中有这个编译器命令行选项:

钩子/Gh (启用_penter钩子功能)

导致在每个方法或函数开始时调用_penter函数。

_penter函数不是任何库的一部分,您可以为_penter提供定义。

除非您计划显式调用_penter,否则不需要提供原型。该函数必须看起来像具有以下原型,并且必须在进入时推送所有寄存器的内容,并在退出时弹出未更改的内容:

代码语言:javascript
运行
复制
void __declspec(naked) _cdecl _penter( void );
票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5081123

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档