如何在C和C++中实现装饰器

sha*_*eel 11 c c++ decorator

我有C和C++的情况,可以用类似装饰器的Python来解决这个问题:我很少有一些函数,我想用其他东西包装,以便在函数输入之前执行某些语句当它离开时,执行其他一些功能.

例如,我在库C文件中有一些函数,当调用它们时应锁定信号量,并在将控件返回给被调用者之前,应该释放信号量.没有锁,他们有以下结构:

int f1(int)
{
    ...
    ... 
}

int f2(char*)
{
    ....
}

int f3(blabla)
{
    ....
}

... fn(...)
Run Code Online (Sandbox Code Playgroud)

我想定义一个全局信号量,在调用每个函数之前应该锁定它们,并在返回函数时释放它们.我想尽可能简单地做到这一点; 接近这个的东西:

#lockprotected
int f1(int)
{
   ... /* nothing changed over here */
}
#endlockprotected
Run Code Online (Sandbox Code Playgroud)

或类似的东西

int f1(int)
{
   ... /* nothing changed over here */
}
#lockprotected f1
Run Code Online (Sandbox Code Playgroud)

我不想要的是:

  1. 更改函数名称,因为它们是库函数,并且从许多位置调用.
  2. 在返回调用之前显式放置任何语句,因为大多数函数之间都有许多早期返回.或者就此而言,改变函数的任何内部.

什么是最优雅的方式?

Jay*_*ker 16

使用RAII(资源获取是初始化)来定义互斥锁上的锁定.这将允许您忘记第2点,即,您不需要跟踪return语句以释放锁定.

class Lock {
public:
    Lock () { // acquire the semaphore }
    ~Lock () { // release the semaphore }
}
Run Code Online (Sandbox Code Playgroud)

接下来在函数的开头创建此类的对象,即

int f1 (int) {
    Lock l;
    // forget about release of this lock
    // as ~Lock() will take care of it
}
Run Code Online (Sandbox Code Playgroud)

这方面的一个优点是即使在抛出异常的情况下f1(),您仍然不必担心释放锁.退出函数之前,所有堆栈对象都将被销毁.

  • 一个显而易见的问题是,你可能会保护太多的功能......而且互斥体通常不是可重入的. (3认同)
  • +1 RAII 是 C++ 的实现方式。f1 函数也必须被包装。这可以通过一个简单的模板函数(会稍微混淆代码)或仅通过创建简单的包装器来完成,如 frunsi 所解释的。 (2认同)

sme*_*lin 11

如果你真的想要一个C解决方案,你可以使用以下宏:

#define LOCK   lock( &yourglobalsemaphore )
#define UNLOCK unlock( &yourglobalsemaphore )

#define LOCKED_FUNCTION_ARG1(TRet, FuncName, TArg1, Arg1Name ) \
TRet FuncName( TArg1 Arg1Name ) { \
 LOCK; \
 TRet ret = FuncName##_Locked( Arg1Name ); \
 UNLOCK; \
 return ret \
} \
TRet FuncName##_Locked(TArg1 Arg1Name )

#define LOCKED_FUNCTION_ARG2(TRet FuncName, TArg1, Arg1Name, TArg2, Arg2Name) \
//...etc
Run Code Online (Sandbox Code Playgroud)

但是每个参数计数都需要1个宏(函数应该有一个返回类型).

示例用法:

LOCKED_FUNCTION_ARG1(int, f1, int, myintarg)
{
   //unchanged code here
}
Run Code Online (Sandbox Code Playgroud)