简体   繁体   English

计算一个函数被调用的次数

[英]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继承自AC拥有一个实例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.

相关问题 这个函数被调用了多少次? - How many times is this function called? 计算一次 function 被调用多少次 - Count how many times a function is called in a time 如何执行多次调用的函数,只执行一次! - How to execute a function called many times, only once ! 调用构造函数的次数是多少? - How many times the constructors are called? google mock - 怎么说“必须使用某个参数调用一次函数,但可以使用不同的参数调用多次”? - google mock - how to say “function must be called ONCE with a certain parameter but ok to be called many times with different parameters”? 复制 ctor 在下面被调用了多少次? - How many times the copy ctor is called in the following? 如何返回递归function在C++中被调用了多少次? - how to return how many times has a recursive function been called in C++? 无论我运行同一个应用程序多少次,应用程序(.exe)中的函数都应该只调用一次 - A Function in an application(.exe) should be called only once regardless of how many times I run the same application 跟踪在 C++ 中调用递归函数的次数 - Keep track of how many times a recursive function has been called in C++ 在curl_easy_setopt()中设置的回调函数将被调用多少次? - How many times the callback function would be called which is set in curl_easy_setopt()?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM