簡體   English   中英

計算一個函數被調用的次數

[英]Counting how many times a function is called

我想統計一個函數被調用的次數,這樣,如果多次調用該函數,就會向開發人員通知一些錯誤(通過日志記錄或斷言等)。 我希望此代碼可以良好定義和隔離,以便可以輕松地移植到許多函數和成員函數中。 就像這樣簡單:

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 ++沒有反射功能,是否有可能以某種方式實現類似目標?

對於獨立函數或靜態類方法,可以使用靜態局部變量:

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__);
    ...
}

反射不是必需的,因為調用者稱為編譯時間。 C ++ 11有一個內置的__func__ ,它的計算結果為純C字符串,即該函數的未經修飾的名稱。 還有typeid(*this).name()來獲取*this后面的類的錯誤名稱。

因此,定義一個維護一組字符串並具有單個方法announce_call 在定義的每個類中放置該類的實例,可能是通過從具有protected實例的人那里繼承而來。

調用announce_call提供函數名稱和類名稱。 如果函數名稱已經在集合中,請在函數名稱和類名稱中記錄一個錯誤。 否則,將其添加到集合中。

如果需要,為不屬於類的函數提供一個全局實例。

因此,每類凈語法成本為:添加一個額外的基類,在每個計數函數的開頭添加一個額外的行。

繼承提供了一個主要警告:因為this總是指向該函數所屬的事物的一個實例,如果B繼承自AC擁有一個實例B但是從A調用了兩次方法,則日志將顯示對A的兩次調用,而不是比B

我認為這與單個宏所能達到的效果非常接近:

#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM