成员函数中的静态变量

Posted

技术标签:

【中文标题】成员函数中的静态变量【英文标题】:Static variables in member functions 【发布时间】:2011-09-07 13:51:58 【问题描述】:

谁能解释一下在 C++ 中是如何工作的。

给定以下类:

class A 
   void foo() 
      static int i;
      i++;
   

如果我声明A 的多个实例,在一个实例上调用foo() 是否会在所有实例上增加静态变量i?还是只有它被调用的那个?

我假设每个实例都有自己的i 副本,但单步执行我拥有的一些代码似乎表明并非如此。

【问题讨论】:

【参考方案1】:

因为class A 是一个非模板类,而A::foo() 是一个非模板函数。程序内只有一份static int i

A 对象的任何实例都会影响相同的i,并且i 的生命周期将在整个程序中保持不变。添加示例:

A o1, o2, o3;
o1.foo(); // i = 1
o2.foo(); // i = 2
o3.foo(); // i = 3
o1.foo(); // i = 4

【讨论】:

感谢你的好例子!是否有一种方法可以实际实现使static int i 的范围特定于实例的东西,例如o1.foo(); // i = 1$o2.foo(); // i = 1 ...? 虽然这可能不是您正在寻找的样式,但将 i 设为 A 类的私有数据成员会产生您所描述的效果。如果您担心名称冲突,您可以添加前缀,例如 m_ 来指示 i 的状态。 请提一下如果类和方法被模板化会发生什么。 @ytobi,在这种情况下,对于普通/模板类的模板化方法的每个实例,将创建一个单独的静态变量。该变量将仅适用于这些类型。例如template<typename T> void foo (T t) ...。现在foo<int> 将有一个static int i(比如foo<int>::i),而foo<string> 将有一个单独的static int i(比如foo<string>::i)等等。对于foo<int>i 将单独递增,而不是从foo<string> 递增。希望能消除疑虑。 澄清一下,您需要在 OP 的代码中设置 i = 0; 才能获得此结果。【参考方案2】:

不幸的是,关键字 static 在 C++ 中有几个不同的不相关的含义

    当用于数据成员时,表示数据在类中分配,而不是在实例中。

    当用于函数内部的数据时,表示数据是静态分配的,在第一次进入块时初始化并持续到程序退出。此外,该变量仅在函数内部可见。局部静态的这一特殊功能通常用于实现单例的惰性构造。

    1234563变量在其他编译单元中将不可访问或可见。

我强调了对每次使用最重要的部分。使用 (3) 有点不鼓励使用未命名的命名空间,它也允许未导出的类声明。

在您的代码中,static 关键字与含义数字 2 一起使用,与类或实例无关...它是 函数 的变量,并且只有一个副本。

正如 iammilind 所说,如果函数是模板函数,则该变量可能有多个实例(因为在这种情况下,函数本身确实可以在程序中的许多不同副本中出现)。即使在那种情况下,课程类和实例也无关紧要......请参见以下示例:

#include <stdio.h>

template<int num>
void bar()

    static int baz;
    printf("bar<%i>::baz = %i\n", num, baz++);


int main()

    bar<1>(); // Output will be 0
    bar<2>(); // Output will be 0
    bar<3>(); // Output will be 0
    bar<1>(); // Output will be 1
    bar<2>(); // Output will be 1
    bar<3>(); // Output will be 1
    bar<1>(); // Output will be 2
    bar<2>(); // Output will be 2
    bar<3>(); // Output will be 2
    return 0;

【讨论】:

有人参考过“有点不赞成使用未命名的命名空间”吗? @austinmarton:短语“在 C++ 中不推荐使用静态来表示‘本地翻译单元’。使用未命名的命名空间 (8.2.5.1)”出现在我的 C++ 编程语言中版(第 10 版,1999 年 9 月),第 819 页。 @iammilind (& OP) static 确实有几个不同的含义;但是,我看不出说这些含义“不相关”是合理的。它总是意味着,“每个 只有一个,它超越了 。” @Andrew: static 在编译单元级别的意思是相反的(它的意思是“本地到编译单元”)【参考方案3】:

函数内的静态变量

在函数内部创建的静态变量存储在程序的静态内存而不是堆栈上。

静态变量初始化将在第一次调用函数时完成。

静态变量会在多个函数调用中保留值

静态变量的生命周期是程序

例子

#include <iostream>

using namespace std;

class CVariableTesting 

    public:
    
    void FuncWithStaticVariable();
    void FuncWithAutoVariable();

;

void CVariableTesting::FuncWithStaticVariable()

    static int staticVar = 0; //staticVar is initialised by 0 the first time
    cout<<"Variable Value : "<<staticVar<<endl;
    staticVar++;

void CVariableTesting::FuncWithAutoVariable()

    int autoVar = 0;
    cout<<"Variable Value : "<<autoVar<<endl;
    autoVar++;

    

int main()

    CVariableTesting objCVariableTesting;
    cout<<"Static Variable";
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    objCVariableTesting.FuncWithStaticVariable();
    
    cout<<endl;
    cout<<"Auto Variable";
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    objCVariableTesting.FuncWithAutoVariable();
    
    return 0;

输出:

静态变量

变量值:0 变量值:1 变量值:2 变量值:3 变量值:4

自动变量

变量值:0 变量值:0 变量值:0 变量值:0 变量值:0

【讨论】:

“地址”会比“价值”更好吗?值发生变化,它不是 const 是的。我们也可以用地址显示。 我的意思是,而不是“静态变量将在多个函数调用中保留值”->“静态变量将在多个函数调用中保留内存地址(即使它的值发生变化)”。跨度> 如果函数是在类中定义的,并且类定义在库中和跨库中包含多次,会发生什么情况,它在程序中仍然是一个吗?【参考方案4】:

简化答案:

静态变量,无论它们是(非模板化)class 或(非模板化)函数的成员,在技术上都表现得像一个全局标签,其范围仅限于 class 或函数。

【讨论】:

没有。全局变量在程序启动时初始化,函数静态变量在第一次使用时初始化。这是一个很大的区别。 我不认为会发生这种情况。但是,无论如何,这应该是特定于编译器的。 那你想错了:C++ 标准中的 3.6.1 规定,命名空间范围对象的构造和静态存储持续时间发生在启动时; 6.7 (4) 规定通常“......这样的变量在控制第一次通过其声明时被初始化;这样的变量在其初始化完成时被认为已初始化”。顺便说一下,这种首次使用时的初始化对于实现惰性单例构造非常方便。 3.7.4:“具有静态存储持续时间的块范围实体的常量初始化(3.6.2),如果适用,在其块首次进入之前执行。允许提前执行实现在允许实现在命名空间范围(3.6.2)中静态初始化具有静态或线程存储持续时间的变量的相同条件下,初始化具有静态或线程存储持续时间的其他块范围变量。否则,首先初始化此类变量时间控制通过它的声明;" 然而很奇怪:1)对于常量初始化,讨论是否可以在第一次进入块之前初始化局部静态是无关紧要的(变量只在块内可见,常量初始化不会产生副作用); 2)您的帖子中没有提到常量初始化; 3) 局部静态对于像MyClass&amp; instance() static MyClass x("config.ini"); return x; 这样的非常量初始化非常有用 - 一个有效的单线程使用的可移植实现正是因为局部静态并不简单地像一个全局变量,尽管你说了什么。

以上是关于成员函数中的静态变量的主要内容,如果未能解决你的问题,请参考以下文章

C++类中的静态成员函数以及静态成员变量

c++中静态成员变量和静态成员函数(笔试经历)

C++类中的静态成员变量与静态成员函数的使用

关于类中静态成员函数和静态成员变量的知识点

关于C++静态成员函数访问非静态成员变量的问题

MFC中静态成员函数调用其他类的非静态变量