[英]Counting how many times a function is called
I want to count how many times a function is called, so that if it is called more than once, some error is notified to the developers (via logging, or asserting, and so on). 我想统计一个函数被调用的次数,这样,如果多次调用该函数,就会向开发人员通知一些错误(通过日志记录或断言等)。 I would like this code to be well defined and isolated so that it is easily portable across many function and member functions as well. 我希望此代码可以良好定义和隔离,以便可以轻松地移植到许多函数和成员函数中。 Something as easy as: 就像这样简单:
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
}
}
Is it possible in C++, since it does not have reflection, to achieve something like that somehow? 由于C ++没有反射功能,是否有可能以某种方式实现类似目标?
For standalone functions, or static class methods, you can use a static local variable: 对于独立函数或静态类方法,可以使用静态局部变量:
void function()
{
static int num_called = 0;
if( ++num_called > 1 )
{
// do something to handle the error
}
...
}
For non-static class methods, use a class data member for each method, allowing individual instances of the class to do their own tracking: 对于非静态类方法,请为每个方法使用类数据成员,以允许类的各个实例进行自己的跟踪:
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
}
...
}
If the error handling is always the same, consider extracting it to a reusable helper: 如果错误处理始终相同,请考虑将其提取到可重用的帮助器中:
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();
...
}
Alternatively: 或者:
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__);
...
}
Reflection isn't necessary, because the caller is known as compile time. 反射不是必需的,因为调用者称为编译时间。 C++11 has a built-in __func__
which evaluates as a plain-C string that is the unadorned name of the function. C ++ 11有一个内置的__func__
,它的计算结果为纯C字符串,即该函数的未经修饰的名称。 There is also typeid(*this).name()
to get the mangled name of the class behind *this
. 还有typeid(*this).name()
来获取*this
后面的类的错误名称。
So define a class that maintains a set of strings and has a single method, announce_call
. 因此,定义一个维护一组字符串并具有单个方法announce_call
。 Put an instance of that class in every class you define, possibly by inheriting from someone that has a protected
instance. 在定义的每个类中放置该类的实例,可能是通过从具有protected
实例的人那里继承而来。
Call announce_call
providing the function name and class name. 调用announce_call
提供函数名称和类名称。 If the function name is already within the set, log an error with it and the class name. 如果函数名称已经在集合中,请在函数名称和类名称中记录一个错误。 Otherwise add it to the set. 否则,将其添加到集合中。
Provide a global instance if desired, for functions that do not belong to classes. 如果需要,为不属于类的函数提供一个全局实例。
So net per-class syntax cost is: adding an extra base class, adding an extra line at the start of every counted function. 因此,每类净语法成本为:添加一个额外的基类,在每个计数函数的开头添加一个额外的行。
Inheritance provides the main caveat: since this
always points to an instance of the thing the function belongs to, if B
inherits from A
and C
owns an instance B
but calls a method from A
twice, the log will show a double call to A
rather than to B
. 继承提供了一个主要警告:因为this
总是指向该函数所属的事物的一个实例,如果B
继承自A
而C
拥有一个实例B
但是从A
调用了两次方法,则日志将显示对A
的两次调用,而不是比B
。
I think this is as close as you can get with a single macro: 我认为这与单个宏所能达到的效果非常接近:
#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
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.