我想计算调用一个函数的次数,这样如果多次调用它,会向开发人员通知一些错误(通过日志记录或断言等)。我希望这个代码能够很好地定义和隔离,以便它可以轻松地在许多函数和成员函数中移植。有点简单:
void function( )
{
if( is_called_more_than_once( ) )
{
// do something to handle the error
}
}
void AClass::method( )
{
if( is_called_more_than_once( ) )
{
// do something to handle the error
}
}
是否有可能在C ++中,因为它没有反射,以某种方式实现类似的东西?
答案 0 :(得分:3)
对于独立函数或静态类方法,您可以使用静态局部变量:
void function()
{
static int num_called = 0;
if( ++num_called > 1 )
{
// do something to handle the error
}
...
}
对于非静态类方法,请为每个方法使用类数据成员,允许类的各个实例进行自己的跟踪:
class AClass
{
private:
int num_method1_called;
int num_method2_called;
public:
AClass();
void method1();
void method2();
...
};
AClass::AClass() :
num_method1_called(0),
num_method2_called(0)
{
}
void AClass::method1()
{
if( ++num_method1_called > 1 )
{
// do something to handle the error
}
...
}
void AClass::method2()
{
if( ++num_method2_called > 1 )
{
// do something to handle the error
}
...
}
如果错误处理始终相同,请考虑将其解压缩为可重用的帮助程序:
struct callTracker
{
int counter;
callTracker() : counter(0) {}
void called()
{
if( ++counter > 1 )
{
// do something to handle the error
}
}
};
void function( )
{
static callTracker tracker;
tracker.called();
...
}
class AClass
{
private:
callTracker method1_tracker;
callTracker method2_tracker;
public:
void method1();
void method2();
...
};
void AClass::method1()
{
method1_tracker.called();
...
}
void AClass::method2()
{
method2_tracker.called();
...
}
可替换地:
struct singleCallTracker
{
int counter;
singleCallTracker() : counter(0) {}
void called()
{
if( ++counter > 1 )
{
// do something to handle the error
}
}
};
struct multiCallTracker
{
std::map<std::string, singleCallTracker> trackers;
void called(const std::string &name)
{
trackers[name].called();
}
};
void function()
{
static singleCallTracker tracker;
tracker.called();
...
}
class AClass
{
private:
multiCallTracker method_tracker;
public:
void method1();
void method2();
...
};
void AClass::method1()
{
method_tracker.called(__FUNC__);
...
}
void AClass::method2()
{
method_tracker.called(__FUNC__);
...
}
答案 1 :(得分:1)
反射是不必要的,因为调用者称为编译时。 C ++ 11有一个内置的__func__
,它被评估为一个普通的C字符串,它是该函数的简单名称。还有typeid(*this).name()
来获取*this
后面的类的错位名称。
因此,定义一个维护一组字符串的类,并且只有一个方法announce_call
。在您定义的每个类中放置该类的实例,可能通过从具有protected
实例的人继承。
调用announce_call
提供函数名称和类名称。如果函数名称已在集合中,请使用它和类名称记录错误。否则将其添加到集合中。
如果需要,为不属于类的函数提供全局实例。
因此,每类净语法成本是:添加额外的基类,在每个计数函数的开头添加额外的行。
继承提供了主要警告:由于this
始终指向函数所属事物的实例,如果B
继承自A
且C
拥有实例B
但是从A
调用两次方法,日志会显示对A
的双重调用,而不是B
。
答案 2 :(得分:0)
我认为这与使用单个宏一样接近:
#define if_called_more_than_once() \
static int s_nTimesCalled = 0; if (++s_nTimesCalled > 1)
void function( )
{
if_called_more_than_once()
{
// do something to handle the error
}
}