简体   繁体   中英

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?

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. There is also typeid(*this).name() to get the mangled name of the class behind *this .

So define a class that maintains a set of strings and has a single method, announce_call . Put an instance of that class in every class you define, possibly by inheriting from someone that has a protected instance.

Call announce_call providing the function name and class name. 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 .

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
    } 
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM