为啥方法局部静态变量绑定到类而不是实例?

Posted

技术标签:

【中文标题】为啥方法局部静态变量绑定到类而不是实例?【英文标题】:Why are method-local static variables bound to class and not to instances?为什么方法局部静态变量绑定到类而不是实例? 【发布时间】:2020-04-04 09:49:23 【问题描述】:

在这个班级

struct A

    ...
    void method()
    
        static x=0;
        x++;
        ...
    

对于 A 的每个实例,对 method() 的调用将为所有实例增加 x

我希望 x 仅在调用 method() 的实例中增加,而不会影响任何其他实例的 x。这有效地将方法局部静态变量绑定到类,并且作为一个附带问题:为什么我不能有类级静态变量(只有 const 的),我希望它的行为与方法局部静态变量当前一样。

我知道我可以用一些额外的代码“修复”这个问题,但仍然想了解这种行为的原因。

一些代码给那些想看到行为的人:

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

inline void PRINTSTRING(const std::string &s)  std::cout << s; std::cout.flush(); 
template<typename...T> void say(T...t)  std::stringstream ss; (ss<<...<<t); PRINTSTRING(ss.str()); 
template<typename...T> std::string says(T...t)  std::stringstream ss; (ss<<...<<t); return ss.str(); 
template<typename...T> bool sayerr(T...t)  say("Error: ", t...); return false; 

struct A  std::string sa"A"; void who()  static int a=0; a++; say(says(sa, " a=", a, "\n")); ;

std::vector<A*> AList;

void killas()  while (!AList.empty())  auto it=AList.begin(); delete (*it); AList.erase(it); 
A* newa(const std::string &s)  A *pA=new A; if (pA)  pA->sa=s; AList.push_back(pA);  return pA; 
void showas()  if (AList.empty()) say("-empty-\n"); else for (auto p:AList) p->who(); 

int main(int argc, const char *argv[])

    say("\ntesting if a static var in a method is bound to instance or to class ...\n\nexpect 'empty'\n");
    showas();
    newa("one"); newa("two"); newa("three"); newa("four"); newa("five");
    say("\nif bound to instance expect all 1's\n");
    showas();
    say("\nif bound to instance expect all 2's\n");
    showas();
    killas();
    return 0;

【问题讨论】:

static 表示静态存储:该函数的每次执行都使用相同的地址为x 静态分配存储。就其在 asm 中的工作方式而言,它与全局 var 或文件范围的 static 完全相同,只是编译器只允许您从声明它的范围访问它。 如果方法定义可以为对象添加更多状态(每个实例数据),sizeof(class T) 将需要查看每个成员的定义,而不仅仅是声明函数,强制在.h 文件中定义所有类成员函数。除非这种可能性仅限于类声明中定义的成员函数?但这也会很奇怪。如果你想要一个私有成员变量,声明一个成员变量。顺便说一句,你可以拥有类范围的非常量 static 成员变量,例如 class foo static int x; ; 你似乎认为你不能? godbolt.org/z/5kUfxG 【参考方案1】:

静态成员属于类而不是实例,方法局部静态各种也是这样。你只需要一个普通的类私有成员。

【讨论】:

【参考方案2】:

发现 this 虽然没有解释行为的原因,但确实很好地描述了它的用途。

关于storage duration,它说:

在块范围内声明的变量带有说明符 static 或 thread_local (C++11 起) 有静态或线程 (C++11 起) 存储时长但被初始化的第一次控制 通过他们的声明(除非他们的初始化是 零或常量初始化,可以在之前执行 该块首先进入)。在所有进一步的调用中,声明是 跳过。

还有一点:

同一个内联的所有定义中的函数局部静态对象 function (可能是隐式内联的)都指的是同一个 在一个翻译单元中定义的对象。

我没有意识到这一点,现在知道它肯定有助于防止我的代码中出现意外的“功能”。

【讨论】:

以上是关于为啥方法局部静态变量绑定到类而不是实例?的主要内容,如果未能解决你的问题,请参考以下文章

静态关键字static

实例局部静态变量(java)

静态变量,静态方法,静态代码块,静态内部类

Java static keyword

局部变量,实例变量,静态变量

Java 局部变量实例变量类变量(静态变量)区别