获取函数的调用标识符或地址

时间:2016-09-28 20:25:37

标签: c++

假设我有这段代码:

class MyClass
{
public:
   void SomeFunction()
   {
   // Find somehow if this is first, second, or third call of a function in a main loop
   // If the function is called first time create new variables that will be used just for this function call
   }
};

MyClass myClassObject;

 int main()
{
    myClassObject.SomeFunction(); // First call
    myClassObject.SomeFunction(); // Second call
    myClassObject.SomeFunction(); // Third call
}

我如何知道内部功能是多少通话? 请注意,我可能会在代码中放置100个函数调用。此外,这应该适用于Windows上的Visual Studio和Mac上的Clang。

我有一个解决方法:

void SomeFunction(const char* indetifier = "address")
{
     CheckAddress(indetifier); // This will check if address is stored. If it is not, create variables, if it is, if addresses matches use variables that are tied to that address.
}

我尝试不将新字符串分配给“indetifier”并让它使用默认字符串(“address”)。这当然没有用,因为编译器会优化“indetifier”,所以我想可能一个解决方案是禁用该变量的优化,但我没有,因为应该有一些更优雅的解决方案。

还有一件事出现在我脑海中,也许我可以强制内联一个函数,然后得到它的地址,但这也像坏的解决方法一样。

我还可以为每个调用创建新类,但我想避免这种情况,因为会有很多函数调用,我不想考虑100个不同的名称。

如果有一种方法只在第一次调用时创建类对象,那就太棒了。

我希望你能理解我想要的东西,对不起,如果因为我是初学者而没有那么清楚......:D

修改

我不能在类中使用static作为变量,因为我正在开发的软件是一个可以在主机内部加载多个实例的插件,这可能会搞乱变量。我已经测试了静态变量,如果我在任何地方创建“静态int值”,并在插件的一个实例中写入一些内容,这个“值”将针对插件的所有实例进行更新,这不是我想要的。

4 个答案:

答案 0 :(得分:0)

在C ++中,您可以在局部变量上下文中使用static关键字在第一次调用时仅创建一次对象:

#include <iostream>

struct MyObject {
    MyObject() {
        std::cout << "Creating instance " << this << "\n";
    };
};

void foo() {
    static MyObject my_instance;
    std::cout << "... inside function foo ...\n";
}

int main(int argc, const char *argv[]) {
    std::cout << "About to call foo...\n";
    foo();
    std::cout << "... second call ...\n";
    foo();
    std::cout << "... third call ...\n";
    foo();
    return 0;
}

使用上面的代码,您会注意到,在第一次调用MyObject时,只会在对象foo上创建。

请注意,如果您的函数是模板,那么对于模板的每个实例化,您将获得另一个不同的静态变量。例如:

template<int N>
void foo() {
    static MyObject my_instance;
    std::cout << "... inside function foo ...\n";
}

foo<1>()的所有调用都将使用相同的变量,但调用foo<2>()将访问函数的另一个副本(函数模板的另一个实例),它将具有自己的不同静态变量在第一次调用foo<2>()时创建。当程序终止时,所有已初始化的静态变量将在main结束后销毁。

答案 1 :(得分:0)

void SomeFunction()
{
// Find somehow if this is first, second, or third call of a function in a main loop
// If the function is called first time create new variables that will be used just for this function call
}

如果要跟踪每个对象的第一个调用,那么您需要一个成员变量来跟踪为该对象调用SomeFuntion的次数。

如果要独立于对象跟踪第一个调用,则可以使用static函数变量来跟踪为该对象调用SomeFuntion的次数。

答案 2 :(得分:0)

  

我不能在类中使用静态变量,因为我正在开发的软件是一个插件,可能在主机内部加载了多个实例,这可能会搞乱变量。我已经测试了静态变量,如果我创建了例如&#34; static int value&#34;在任何地方,并在插件的一个实例中写一些东西,这个&#34;值&#34;将针对插件的所有实例进行更新,这不是我想要的。

那么制作一个非静态计数器?

class MyClass {
   int count;
public:
   MyClass () : count(0) { }
   void SomeFunction () {
       ++ count;
       // do stuff with 'count'
   }
};

MyClass myClassObject;

int main () {
    myClassObject.SomeFunction(); // First call
    myClassObject.SomeFunction(); // Second call
    myClassObject.SomeFunction(); // Third call
}

或者只是将其作为参数传递......

class MyClass {
public:
   void SomeFunction (int count) {
       // do stuff with 'count'
   }
};

MyClass myClassObject;

int main () {
    myClassObject.SomeFunction(1); // First call
    myClassObject.SomeFunction(2); // Second call
    myClassObject.SomeFunction(3); // Third call
}

但我真的很想知道你实际上想要做什么,我强烈建议你坐下来重新思考这一切,因为这里有许多危险信号/混淆点...... / p>

答案 3 :(得分:0)

如果您只想检查是否是第一个电话,则可以向bool SomeFunction_first_call;添加MyClass,以充当标志。构造函数将bool设置为trueMyClass::SomeFunction()使用条件检查if (SomeFunction_first_call) /* ... */来确定它是否是第一次调用,如下所示:

class MyClass
{
    bool SomeFunction_first_call;

public:
    MyClass() : SomeFunction_first_call(true) {}

    void SomeFunction()
    {
        if (SomeFunction_first_call)
        {
            // This code only executes on first call.
            do_something();

            // Successfully handled first call, set flag to false.
            SomeFunction_first_call = false;
        }

        // This code always executes.
        do_something();
    }
};

同样,如果您只关注前HOWEVER_MANY_CALLS次来电,其中HOWEVER_MANY_CALLS是一个数字,您可以使用以下内容:

#include <cstdint>

class MyClass
{
     uint8_t SomeFunction_calls;

public:
    MyClass() : SomeFunction_calls(0) {}

    void SomeFunction()
    {
        // This segment will be executed until (SomeFunction_calls == HOWEVER_MANY_CALLS).
        // After this, the segment will be skipped, and the counter will no longer increment.
        if (SomeFunction_calls < HOWEVER_MANY_CALLS)
        {
            // This code only executes on first HOWEVER_MANY_CALLS calls.
            do_something();

            // Increment counter.
            ++SomeFunction_calls;
        }

        // This code always executes.
        do_something();
    }
};

确保使用适当签名的变量来表示需要特殊处理的呼叫数量(例如{0}为0..255,uint8_t为256..65,535等)。如果uint16_t的不同实例需要跟踪不同数量的调用,则使用非类型模板参数来指示此情况,并可选地使用默认MyClass来指示计数器应该采用何种类型是

typename

在这种情况下,#include <cstdint> template<uint64_t N, typename T = uint64_t> class MyClass { T SomeFunction_calls; ... void SomeFunction() { if (SomeFunction_calls < N) { ... } ... } }; 将对MyClass<4>的前4个电话进行特殊处理,SomeFunction()将对前4,444,444,444,444,444,444电话进行特殊处理,依此类推。计数器将默认为MyClass<4444444444444444444>,因为它应足够大以容纳该值;当只有少数呼叫需要特殊处理时,您可以指定较小的类型,例如uint64_tMyClass<4, uint8_t>