static 关键字及其在 C++ 中的各种用途

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15235526/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:12:14  来源:igfitidea点击:

The static keyword and its various uses in C++

c++static

提问by Tony The Lion

The keyword staticis one which has several meanings in C++ that I find very confusing and I can never bend my mind around how its actually supposed to work.

这个关键字static在 C++ 中具有多种含义,我觉得这很令人困惑,而且我永远不会考虑它实际上应该如何工作。

From what I understand there is staticstorage duration, which means that it lasts for the lifetime of the program in the case of a global, but when you're talking about a local, it means that it's zero initialized by default.

据我所知,有static存储持续时间,这意味着在全局情况下它会持续整个程序的生命周期,但是当您谈论本地时,这意味着默认情况下它初始化为零。

The C++ Standard says this for class data members with the keyword static:

C++ 标准对带有关键字的类数据成员说static

3.7.1 Static storage duration [basic.stc.static]

3.7.1 静态存储时长 [basic.stc.static]

3 The keyword static can be used to declare a local variable with static storage duration.

4 The keyword static applied to a class data member in a class definition gives the data member static storage duration.

3 关键字static 可用于声明具有静态存储期的局部变量。

4 在类定义中应用于类数据成员的关键字 static 给出了数据成员静态存储持续时间。

What does it mean with local variable? Is that a function local variable? Because there's also that when you declare a function local as staticthat it is only initialized once, the first time it enters this function.

局部变量是什么意思?那是函数局部变量吗?因为还有当你声明一个本地函数时static,它只初始化一次,第一次进入这个函数。

It also only talks about storage duration with regards to class members, what about it being non instance specific, that's also a property of staticno? Or is that storage duration?

它也只讨论关于类成员的存储持续时间,它是非实例特定的,那也是否的属性static?或者是那个存储期限?

Now what about the case with staticand file scope? Are all global variables considered to have static storage duration by default? The following (from section 3.7.1) seems to indicate so:

现在static文件范围的情况如何?默认情况下,是否所有全局变量都被认为具有静态存储持续时间?以下(来自第 3.7.1 节)似乎表明了这一点:

1 All variables which do not have dynamic storage duration, do not have thread storage duration, and are not localhave static storage duration. The storage for these entities shall last for the duration of the program (3.6.2, 3.6.3)

1 所有没有动态存储期、没有线程存储期、非局部变量都有静态存储期。这些实体的存储应在程序期间持续(3.6.2、3.6.3)

How does staticrelate to the linkage of a variable?

如何static涉及变量的联动?

This whole statickeyword is downright confusing, can someone clarify the different uses for it English and also tell me whento initialize a staticclass member?

这整个static关键字完全令人困惑,有人可以澄清它的不同用途英语并告诉我何时初始化static类成员吗?

采纳答案by Mooing Duck

Variables:

变量:

staticvariables exist for the "lifetime" of the translation unit that it's defined in, and:

static变量存在于它在 中定义翻译单元的“生命周期” ,并且:

  • If it's in a namespace scope (i.e. outside of functions and classes), then it can't be accessed from any other translation unit. This is known as "internal linkage" or "static storage duration". (Don't do this in headers except for constexpr. Anything else, and you end up with a separate variable in each translation unit, which is crazy confusing)
  • If it's a variable in a function, it can't be accessed from outside of the function, just like any other local variable. (this is the local they mentioned)
  • class members have no restricted scope due to static, but can be addressed from the class as well as an instance (like std::string::npos). [Note: you can declarestatic members in a class, but they should usually still be definedin a translation unit (cpp file), and as such, there's only one per class]
  • 如果它在命名空间范围内(即在函数和类之外),则不能从任何其他翻译单元访问它。这被称为“内部链接”或“静态存储持续时间”。(不要在标题中执行此操作,除了constexpr. 其他任何内容,您最终在每个翻译单元中都有一个单独的变量,这很令人困惑)
  • 如果它是函数中的变量,则不能从函数外部访问它,就像任何其他局部变量一样。(这是他们提到的当地)
  • 由于static,类成员没有受限制的范围,但可以从类和实例(如std::string::npos)中寻址。[注:你可以声明在类的静态成员,但他们通常应该仍然可以定义在一个翻译单元(CPP文件),正因为如此,有每类仅一个]

locations as code:

位置作为代码:

static std::string namespaceScope = "Hello";
void foo() {
    static std::string functionScope= "World";
}
struct A {
   static std::string classScope = "!";
};

Before any function in a translation unit is executed (possibly after mainbegan execution), the variables with static storage duration (namespace scope) in that translation unit will be "constant initialized" (to constexprwhere possible, or zero otherwise), and then non-locals are "dynamically initialized" properly in the order they are defined in the translation unit(for things like std::string="HI";that aren't constexpr). Finally, function-local statics will be initialized the first time execution "reaches" the line where they are declared. All staticvariables all destroyed in the reverse order of initialization.

在执行翻译单元中的任何函数之前(可能在main开始执行之后),该翻译单元中具有静态存储持续时间(命名空间范围)的变量将被“常量初始化”(constexpr尽可能初始化,否则为零),然后非本地人按照它们在翻译单元中定义的顺序正确“动态初始化” (对于类似的东西std::string="HI";不是constexpr)。最后,函数局部静态将在第一次执行“到达”声明它们的行时被初始化。所有static变量都按照与初始化相反的顺序销毁。

The easiest way to get all this right is to make all static variables that are not constexprinitialized into function static locals, which makes sure all of your statics/globals are initialized properly when you try to use them no matter what, thus preventing the static initialization order fiasco.

使这一切正确的最简单的方法是将所有未constexpr初始化的静态变量设置为函数静态局部变量,这确保无论在什么情况下尝试使用它们时,所有静态变量/全局变量都已正确初始化,从而防止静态初始化订购惨败

T& get_global() {
    static T global = initial_value();
    return global;
}

Be careful, because when the spec says namespace-scope variables have "static storage duration" by default, they mean the "lifetime of the translation unit" bit, but that does notmean it can't be accessed outside of the file.

要小心,因为当规范说的命名空间范围变量有“静态存储”在默认情况下,他们的意思是位“翻译单元的一生”,但这并不意味着它不能被访问的文件之外。

Functions

职能

Significantly more straightforward, staticis often used as a class member function, and only very rarely used for a free-standing function.

明显更直接,static通常用作类成员函数,很少用于独立函数。

A static member function differs from a regular member function in that it can be called without an instance of a class, and since it has no instance, it cannot access non-static members of the class. Static variables are useful when you want to have a function for a class that definitely absolutely does not refer to any instance members, or for managing staticmember variables.

静态成员函数与普通成员函数的不同之处在于它可以在没有类的实例的情况下被调用,并且由于它没有实例,它不能访问类的非静态成员。当您想要为绝对不引用任何实例成员的类或管理static成员变量的类提供函数时,静态变量很有用。

struct A {
    A() {++A_count;}
    A(const A&) {++A_count;}
    A(A&&) {++A_count;}
    ~A() {--A_count;}

    static int get_count() {return A_count;}
private:
    static int A_count;
}

int main() {
    A var;

    int c0 = var.get_count(); //some compilers give a warning, but it's ok.
    int c1 = A::get_count(); //normal way
}

A staticfree-function means that the function will not be referred to by any other translation unit, and thus the linker can ignore it entirely. This has a small number of purposes:

static自由函数意味着该功能将不被任何其他翻译单元被称为,因此接头可以完全忽略它。这有几个目的:

  • Can be used in a cpp file to guarantee that the function is never used from any other file.
  • Can be put in a header and every file will have it's own copy of the function. Not useful, since inline does pretty much the same thing.
  • Speeds up link time by reducing work
  • Can put a function with the same name in each translation unit, and they can all do different things. For instance, you could put a static void log(const char*) {}in each cpp file, and they could each all log in a different way.
  • 可以在 cpp 文件中使用,以保证该函数永远不会在任何其他文件中使用。
  • 可以放在标题中,每个文件都有自己的函数副本。没有用,因为内联几乎做同样的事情。
  • 通过减少工作来加快链接时间
  • 可以在每个翻译单元中放置一个同名的函数,它们都可以做不同的事情。例如,您可以static void log(const char*) {}在每个 cpp 文件中放置一个,它们都可以以不同的方式登录。

回答by Luchian Grigore

Static storage duration means that the variable resides in the same place in memory through the lifetime of the program.

静态存储持续时间意味着变量在程序的整个生命周期内都驻留在内存中的同一位置。

Linkage is orthogonal to this.

链接与此正交。

I think this is the most important distinction you can make.Understand this and the rest, as well as remembering it, should come easy (not addressing @Tony directly, but whoever might read this in the future).

我认为这是您可以做出的最重要的区别。理解这一点和其余部分,以及记住它,应该很容易(不是直接解决@Tony,而是将来可能会阅读此内容的人)。

The keyword staticcan be used to denote internal linkage andstatic storage, but in essence these are different.

关键字static可以用来表示内部链接静态存储,但本质上它们是不同的。

What does it mean with local variable? Is that a function local variable?

局部变量是什么意思?那是函数局部变量吗?

Yes. Regardless of when the variable is initialized (on first call to the function and when execution path reaches the declaration point), it will reside in the same place in memory for the life of the program. In this case, staticgives it static storage.

是的。无论变量何时初始化(在第一次调用函数时以及执行路径到达声明点时),它都会在程序的整个生命周期中驻留在内存中的同一位置。在这种情况下,static给它静态存储。

Now what about the case with static and file scope? Are all global variables considered to have static storage duration by default?

现在静态和文件范围的情况如何?默认情况下,是否所有全局变量都被认为具有静态存储持续时间?

Yes, all globals have by definition static storage duration (now that we cleared up what that means). Butnamespace scoped variables aren't declared with static, because that would give them internal linkage, so a variable per translation unit.

是的,根据定义,所有全局变量都具有静态存储持续时间(现在我们已经弄清楚了这意味着什么)。但是命名空间范围的变量不是用 声明的static,因为这会给它们提供内部链接,所以每个翻译单元都有一个变量。

How does static relate to the linkage of a variable?

静态如何与变量的链接相关?

It gives namespace-scoped variables internal linkage. It gives members and local variables static storage duration.

它提供命名空间范围的变量内部链接。它为成员和局部变量提供静态存储持续时间。

Let's expand on all this:

让我们扩展所有这些:

//

static int x; //internal linkage
              //non-static storage - each translation unit will have its own copy of x
              //NOT A TRUE GLOBAL!

int y;        //static storage duration (can be used with extern)
              //actual global
              //external linkage
struct X
{
   static int x;     //static storage duration - shared between class instances 
};

void foo()
{
   static int x;     //static storage duration - shared between calls
}

This whole static keyword is downright confusing

整个 static 关键字完全令人困惑

Definitely, unless you're familiar with it. :) Trying to avoid adding new keywords to the language, the committee re-used this one, IMO, to this effect - confusion. It's used to signify different things (might I say, probably opposing things).

当然,除非你熟悉它。:) 为避免在语言中添加新的关键字,委员会重新使用了 IMO,以达到这种效果 - 混淆。它用于表示不同的事物(我可以说,可能是相反的事物)。

回答by ggulgulia

In order to clarify the question, I would rather categorize the usage of 'static' keyword in three different forms:

为了澄清这个问题,我宁愿将 'static' 关键字的用法归类为三种不同的形式:

(A). variables

(一种)。变量

(B). functions

(乙)。职能

(C). member variables/functions of classes

(C)。类的成员变量/函数

the explanation follows below for each of the sub headings:

对每个子标题的解释如下:

(A) 'static' keyword for variables

(A) 变量的 'static' 关键字

This one can be little tricky however if explained and understood properly, it's pretty straightforward.

这个可能有点棘手,但是如果解释和理解得当,它会非常简单。

To explain this, first it is really useful to know about the scope, duration and linkageof variables, without which things are always difficult to see through the murky concept of staic keyword

为了解释这一点,首先了解变量的作用域、持续时间和链接真的很有用,没有这些,事情总是很难看透 staic 关键字的模糊概念

1. Scope: Determines where in the file, the variable is accessible. It can be of two types: (i) Local or Block Scope. (ii) Global Scope

1. 范围:确定变量在文件中的哪个位置是可访问的。它可以有两种类型:(i)本地或块范围。(ii)全球范围

2. Duration: Determines when a variable is created and destroyed. Again it's of two types: (i) Automatic Storage Duration(for variables having Local or Block scope). (ii) Static Storage Duration(for variables having Global Scope or local variables (in a function or a in a code block) with staticspecifier).

2. Duration: 确定一个变量的创建和销毁时间。同样它有两种类型:(i)自动存储持续时间(对于具有本地或块范围的变量)。(ii)静态存储持续时间(对于具有全局作用域的变量或带有静态说明符的局部变量(在函数或代码块中))。

3. Linkage: Determines whether a variable can be accessed (or linked ) in another file. Again ( and luckily) it is of two types: (i) Internal Linkage(for variables having Block Scope and Global Scope/File Scope/Global Namespace scope) (ii) External Linkage(for variables having only for Global Scope/File Scope/Global Namespace Scope)

3. 链接:确定一个变量是否可以在另一个文件中访问(或链接)。同样(幸运的是)它有两种类型:(i)内部链接(对于具有块范围和全局范围/文件范围/全局命名空间范围的变量)(ii)外部链接(对于仅具有全局范围/文件范围/全局命名空间范围)

Let's refer an example below for better understanding of plain global and local variables (no local variables with static storage duration) :

让我们参考下面的例子来更好地理解普通的全局和局部变量(没有静态存储持续时间的局部变量):

//main file
#include <iostream>

int global_var1; //has global scope
const global_var2(1.618); //has global scope

int main()
{
//these variables are local to the block main.
//they have automatic duration, i.e, they are created when the main() is 
//  executed and destroyed, when main goes out of scope
 int local_var1(23);
 const double local_var2(3.14);

 {
/* this is yet another block, all variables declared within this block are 
 have local scope limited within this block. */
// all variables declared within this block too have automatic duration, i.e, 
/*they are created at the point of definition within this block,
 and destroyed as soon as this block ends */
   char block_char1;
   int local_var1(32) //NOTE: this has been re-declared within the block, 
//it shadows the local_var1 declared outside

 std::cout << local_var1 <<"\n"; //prints 32

  }//end of block
  //local_var1 declared inside goes out of scope

 std::cout << local_var1 << "\n"; //prints 23

 global_var1 = 29; //global_var1 has been declared outside main (global scope)
 std::cout << global_var1 << "\n"; //prints 29
 std::cout << global_var2 << "\n"; //prints 1.618

 return 0;
}  //local_var1, local_var2 go out of scope as main ends
//global_var1, global_var2 go out of scope as the program terminates 
//(in this case program ends with end of main, so both local and global
//variable go out of scope together

Now comes the concept of Linkage. When a global variable defined in one file is intended to be used in another file, the linkage of the variable plays an important role.

现在来了联动的概念。当一个文件中定义的全局变量打算在另一个文件中使用时,变量的链接起着重要的作用。

The Linkage of global variables is specified by the keywords: (i) static, and, (ii) extern

全局变量的链接由关键字指定:(i) static, and, (ii) extern

( Now you get the explanation )

(现在你明白了)

static keyword can be applied to variables with local and global scope, and in both the cases, they mean different things. I will first explain the usage of 'static' keyword in variables with global scope ( where I also clarify the usage of keyword 'extern') and later the for those with local scope.

static 关键字可以应用于具有局部和全局作用域的变量,在这两种情况下,它们的含义不同。我将首先解释'static'关键字在具有全局作用域的变量中的用法(我还阐明了关键字'extern'的用法),然后解释了具有局部作用域的变量的用法。

1. Static Keyword for variables with global scope

1. 全局变量的静态关键字

Global variables have static duration, meaning they don't go out of scope when a particular block of code (for e.g main() ) in which it is used ends . Depending upon the linkage, they can be either accessed only within the same file where they are declared (for static global variable), or outside the file even outside the file in which they are declared (extern type global variables)

全局变量具有静态持续时间,这意味着当使用它的特定代码块(例如 main() )结束时,它们不会超出范围。根据链接,它们可以仅在声明它们的同一个文件中访问(对于静态全局变量),或者在文件外部甚至在声明它们的文件外部(外部类型全局变量)

In the case of a global variable having extern specifier, and if this variable is being accessed outside the file in which it has been initialized, it has to be forward declared in the file where it's being used, just like a function has to be forward declared if it's definition is in a file different from where it's being used.

在全局变量具有 extern 说明符的情况下,如果在初始化它的文件之外访问此变量,则必须在使用它的文件中向前声明,就像函数必须向前一样如果它的定义位于与使用位置不同的文件中,则声明。

In contrast, if the global variable has static keyword, it cannot be used in a file outside of which it has been declared.

相反,如果全局变量具有 static 关键字,则不能在已声明它的文件之外使用它。

(see example below for clarification)

(有关说明,请参见下面的示例)

eg:

例如:

//main2.cpp
 static int global_var3 = 23;  /*static global variable, cannot be                            
                                accessed in anyother file */
 extern double global_var4 = 71; /*can be accessed outside this file                  linked to main2.cpp */
 int main() { return 0; }

main3.cpp

main3.cpp

//main3.cpp
#include <iostream>

int main()
{
   extern int gloabl_var4; /*this variable refers to the gloabal_var4
                            defined in the main2.cpp file */
  std::cout << global_var4 << "\n"; //prints 71;

  return 0;
}

now any variable in c++ can be either a const or a non-const and for each 'const-ness' we get two case of default c++ linkage, in case none is specified:

现在c++中的任何变量都可以是const或非常量,对于每个'const-ness',我们得到两种默认c++链接的情况,如果没有指定:

(i) If a global variable is non-const, its linkage is extern by default, i.e, the non-const global variable can be accessed in another .cpp file by forward declaration using the extern keyword (in other words, non const global variables have external linkage ( with static duration of course)). Also usage of extern keyword in the original file where it has been defined is redundant. In this case to make a non-const global variable inaccessible to external file, use the specifier 'static' before the type of the variable.

(i)如果一个全局变量是非常量的,默认情况下它的链接是 extern,即可以通过使用 extern 关键字的前向声明在另一个 .cpp 文件中访问非常量全局变量(换句话说,非常量全局变量变量具有外部链接(当然具有静态持续时间))。在定义它的原始文件中使用 extern 关键字也是多余的。在这种情况下,要使外部文件无法访问非常量全局变量,请在变量类型之前使用说明符“静态”

(ii) If a global variable is const, its linkage is static by default, i.e a const global variable cannot be accessed in a file other than where it is defined, (in other words, const global variables have internal linkage (with static duration of course)). Also usage of static keyword to prevent a const global variable from being accessed in another file is redundant. Here, to make a const global variable have an external linkage, use the specifier 'extern' before the type of the variable

(ii)如果一个全局变量是 const,它的链接默认是静态的,即一个 const 全局变量不能在它定义的文件之外的文件中访问,(换句话说,const 全局变量具有内部链接(具有静态持续时间)当然))。此外,使用 static 关键字来防止在另一个文件中访问 c​​onst 全局变量是多余的。在这里,要使 const 全局变量具有外部链接,请在变量类型之前使用说明符“extern”

Here's a summary for global scope variables with various linkages

这是具有各种链接的全局范围变量的摘要

//globalVariables1.cpp 

// defining uninitialized vairbles
int globalVar1; //  uninitialized global variable with external linkage 
static int globalVar2; // uninitialized global variable with internal linkage
const int globalVar3; // error, since const variables must be initialized upon declaration
const int globalVar4 = 23; //correct, but with static linkage (cannot be accessed outside the file where it has been declared*/
extern const double globalVar5 = 1.57; //this const variable ca be accessed outside the file where it has been declared

Next we investigate how the above global variables behave when accessed in a different file.

接下来我们研究上述全局变量在不同文件中访问时的行为。

//using_globalVariables1.cpp (eg for the usage of global variables above)

// Forward declaration via extern keyword:
 extern int globalVar1; // correct since globalVar1 is not a const or static
 extern int globalVar2; //incorrect since globalVar2 has internal linkage
 extern const int globalVar4; /* incorrect since globalVar4 has no extern 
                         specifier, limited to internal linkage by
                         default (static specifier for const variables) */
 extern const double globalVar5; /*correct since in the previous file, it 
                           has extern specifier, no need to initialize the
                       const variable here, since it has already been
                       legitimately defined perviously */

2. Static Keyword for variables with Local Scope

2. 局部作用域变量的静态关键字

Updates (August 2019) on static keyword for variables in local scope

本地范围内变量的静态关键字更新(2019 年 8 月)

This further can be subdivided in two categories :

这可以进一步细分为两类:

(i) static keyword for variables within a function block, and (ii) static keyword for variables within a unnamed local block.

(i) 功能块内变量的 static 关键字,以及(ii) 未命名局部块内变量的 static 关键字。

(i) static keyword for variables within a function block.

(i) 功能块内变量的静态关键字。

Earlier, I mentioned that variables with local scope have automatic duration, i.e they come to exist when the block is entered ( be it a normal block, be it a function block) and cease to exist when the block ends, long story short, variables with local scope have automatic durationand automatic duration variables (and objects) have no linkage meaning they are not visible outside the code block.

之前,我提到具有局部作用域的变量具有自动持续时间,即它们在进入块时存在(无论是普通块还是功能块),并在块结束时停止存在,长话短说,变量具有局部作用域的自动持续时间和自动持续时间变量(和对象)没有链接,这意味着它们在代码块之外不可见。

If staticspecifier is applied to a local variable within a function block, it changes the duration of the variable from automatic to staticand its life time is the entire duration of the program which means it has a fixed memory location and its value is initialized only once prior to program start up as mentioned in cpp reference(initialization should not be confused with assignment)

如果静态说明符应用于功能块中的局部变量,它将变量的持续时间从自动更改为静态,并且其生命周期是程序的整个持续时间,这意味着它具有固定的内存位置并且其值仅被初始化在cpp 参考中提到的程序启动之前一次(初始化不应与赋值混淆)

lets take a look at an example.

让我们看一个例子。

//localVarDemo1.cpp    
 int localNextID()
{
  int tempID = 1;  //tempID created here
  return tempID++; //copy of tempID returned and tempID incremented to 2
} //tempID destroyed here, hence value of tempID lost

int newNextID()
{
  static int newID = 0;//newID has static duration, with internal linkage
  return newID++; //copy of newID returned and newID incremented by 1
}  //newID doesn't get destroyed here :-)


int main()
{
  int employeeID1 = localNextID();  //employeeID1 = 1
  int employeeID2 = localNextID();  // employeeID2 = 1 again (not desired)
  int employeeID3 = newNextID(); //employeeID3 = 0;
  int employeeID4 = newNextID(); //employeeID4 = 1;
  int employeeID5 = newNextID(); //employeeID5 = 2;
  return 0;
}

Looking at the above criterion for static local variables and static global variables, one might be tempted to ask, what the difference between them could be. While global variables are accessible at any point in within the code (in same as well as different translation unit depending upon the const-ness and extern-ness), a static variable defined within a function block is not directly accessible. The variable has to be returned by the function value or reference. Lets demonstrate this by an example:

查看上述静态局部变量和静态全局变量的标准,人们可能会问,它们之间的区别是什么。虽然全局变量可以在代码中的任何点访问(在相同和不同的翻译单元中,取决于const-ness 和extern-ness),但不能直接访问功能块中定义的静态变量。变量必须由函数值或引用返回。让我们通过一个例子来证明这一点:

//localVarDemo2.cpp 

//static storage duration with global scope 
//note this variable can be accessed from outside the file
//in a different compilation unit by using `extern` specifier
//which might not be desirable for certain use case.
static int globalId = 0;

int newNextID()
{
  static int newID = 0;//newID has static duration, with internal linkage
  return newID++; //copy of newID returned and newID incremented by 1
}  //newID doesn't get destroyed here


int main()
{
    //since globalId is accessible we use it directly
  const int globalEmployee1Id = globalId++; //globalEmployeeId1 = 0;
  const int globalEmployee2Id = globalId++; //globalEmployeeId1 = 1;

  //const int employeeID1 = newID++; //this will lead to compilation error since newID++ is not accessible direcly. 
  int employeeID2 = newNextID(); //employeeID3 = 0;
  int employeeID2 = newNextID(); //employeeID3 = 1;

  return 0;
}

More explaination about choice of static global and static local variable could be found on this stackoverflow thread

可以在此 stackoverflow 线程上找到有关选择静态全局变量和静态局部变量的更多说明

(ii) static keyword for variables within a unnamed local block.

(ii) 未命名局部块中变量的静态关键字。

static variables within a local block (not a function block) cannot be accessed outside the block once the local block goes out of scope. No caveats to this rule.

一旦局部块超出范围,就不能在块外访问局部块(不是功能块)内的静态变量。这条规则没有任何警告。

    //localVarDemo3.cpp 
    int main()
    {

      {
          const static int static_local_scoped_variable {99};
      }//static_local_scoped_variable goes out of scope

      //the line below causes compilation error
      //do_something is an arbitrary function
      do_something(static_local_scoped_variable);
      return 0;
    }

C++11 introduced the keyword constexprwhich guarantees the evaluation of an expression at compile time and allows compiler to optimize the code. Now if the value of a static const variable within a scope is known at compile time, the code is optimized in a manner similar to the one with constexpr. Here's a small example

C++11 引入了constexpr保证在编译时对表达式求值并允许编译器优化代码的关键字。现在,如果范围内的静态常量变量的值在编译时已知,则代码会以类似于constexpr. 这是一个小例子

I recommend readers also to look up the difference between constexprand static constfor variables in this stackoverflow thread. this concludes my explanation for the static keyword applied to variables.

我还建议读者在这个 stackoverflow 线程中查找变量constexprstatic const变量之间的区别。我对应用于变量的 static 关键字的解释到此结束。

B. 'static' keyword used for functions

B. 用于函数的 'static' 关键字

in terms of functions, the static keyword has a straightforward meaning. Here, it refers to linkage of the functionNormally all functions declared within a cpp file have external linkage by default, i.e a function defined in one file can be used in another cpp file by forward declaration.

就功能而言,static关键字的含义很直接。这里指的是函数的链接。通常在一个cpp文件中声明的所有函数默认都有外部链接,即一个文件中定义的函数可以通过前向声明在另一个cpp文件中使用。

using a static keyword before the function declaration limits its linkage to internal, i.e a static function cannot be used within a file outside of its definition.

在函数声明之前使用 static 关键字将其链接限制为 internal,即静态函数不能在其定义之外的文件中使用。

C. Staitc Keyword used for member variables and functions of classes

C. 类的成员变量和函数使用的 Staitc 关键字

1. 'static' keyword for member variables of classes

1. 类成员变量的'static'关键字

I start directly with an example here

我直接从这里的例子开始

#include <iostream>

class DesignNumber
{
  private:

      static int m_designNum;  //design number
      int m_iteration;     // number of iterations performed for the design

  public:
    DesignNumber() {     }  //default constructor

   int  getItrNum() //get the iteration number of design
   {
      m_iteration = m_designNum++;
      return m_iteration;
   }
     static int m_anyNumber;  //public static variable
};
int DesignNumber::m_designNum = 0; // starting with design id = 0
                     // note : no need of static keyword here
                     //causes compiler error if static keyword used
int DesignNumber::m_anyNumber = 99; /* initialization of inclass public 
                                    static member  */
enter code here

int main()
{
   DesignNumber firstDesign, secondDesign, thirdDesign;
   std::cout << firstDesign.getItrNum() << "\n";  //prints 0
   std::cout << secondDesign.getItrNum() << "\n"; //prints 1
   std::cout << thirdDesign.getItrNum() << "\n";  //prints 2

   std::cout << DesignNumber::m_anyNumber++ << "\n";  /* no object
                                        associated with m_anyNumber */
   std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 100
   std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 101

   return 0;
}

In this example, the static variable m_designNum retains its value and this single private member variable (because it's static) is shared b/w all the variables of the object type DesignNumber

在此示例中,静态变量 m_designNum 保留其值,并且此单个私有成员变量(因为它是静态的)与对象类型 DesignNumber 的所有变量共享

Also like other member variables, static member variables of a class are not associated with any class object, which is demonstrated by the printing of anyNumber in the main function

也和其他成员变量一样,一个类的静态成员变量不与任何类对象关联,这可以通过main函数中anyNumber的打印来证明

const vs non-const static member variables in class

类中的 const 与非常量静态成员变量

(i) non-const class static member variablesIn the previous example the static members (both public and private) were non constants. ISO standard forbids non-const static members to be initialized in the class. Hence as in previous example, they must be initalized after the class definition, with the caveat that the static keyword needs to be omitted

(i) 非常量类静态成员变量在前面的例子中,静态成员(公共和私有)是非常量。ISO 标准禁止在类中初始化非常量静态成员。因此和前面的例子一样,它们必须在类定义之后初始化,但需要注意的是 static 关键字需要省略

(ii) const-static member variables of classthis is straightforward and goes with the convention of other const member variable initialization, i.e the const static member variables of a class can beinitialized at the point of declaration and they can be initialized at the end of the class declaration with one caveat that the keyword const needs to be added to the static member when being initialized after the class definition.

(ii) 类的 const-static 成员变量这很简单,符合其他 const 成员变量初始化的约定,即类的 const 静态成员变量可以在声明点初始化,也可以在最后初始化类声明的一个警告,即在类定义之后初始化时需要将关键字 const 添加到静态成员中。

I would however, recommend to initialize the const static member variables at the point of declaration. This goes with the standard C++ convention and makes the code look cleaner

但是,我建议在声明时初始化 const 静态成员变量。这符合标准的 C++ 约定并使代码看起来更清晰

for more examples on static member variables in a class look up the following link from learncpp.com http://www.learncpp.com/cpp-tutorial/811-static-member-variables/

有关类中静态成员变量的更多示例,请从 learncpp.com 查找以下链接 http://www.learncpp.com/cpp-tutorial/811-static-member-variables/

2. 'static' keyword for member function of classes

2.类成员函数的'static'关键字

Just like member variables of classes can ,be static, so can member functions of classes. Normal member functions of classes are always associated with a object of the class type. In contrast, static member functions of a class are not associated with any object of the class, i.e they have no *this pointer.

就像类的成员变量可以是静态的一样,类的成员函数也可以是静态的。类的普通成员函数总是与类类型的对象相关联。相反,类的静态成员函数不与类的任何对象相关联,即它们没有 *this 指针。

Secondly since the static member functions of the class have no *this pointer, they can be called using the class name and scope resolution operator in the main function (ClassName::functionName(); )

其次,由于类的静态成员函数没有 *this 指针,因此可以使用主函数中的类名和作用域解析运算符 (ClassName::functionName(); )

Thirdly static member functions of a class can only access static member variables of a class, since non-static member variables of a class must belong to a class object.

第三,类的静态成员函数只能访问类的静态成员变量,因为类的非静态成员变量必须属于类对象。

for more examples on static member functions in a class look up the following link from learncpp.com

有关类中静态成员函数的更多示例,请从 learncpp.com 查找以下链接

http://www.learncpp.com/cpp-tutorial/812-static-member-functions/

http://www.learncpp.com/cpp-tutorial/812-static-member-functions/

回答by Maciej Stachowski

It's actually quite simple. If you declare a variable as static in the scope of a function, its value is preserved between successive calls to that function. So:

其实很简单。如果在函数范围内将变量声明为静态变量,则在对该函数的连续调用之间保留其值。所以:

int myFun()
{
static int i=5;
i++;
return i;
}
int main()
{
printf("%d", myFun());
printf("%d", myFun());
printf("%d", myFun());
}

will show 678instead of 666, because it remembers the incremented value.

将显示678而不是666,因为它会记住增加的值。

As for the static members, they preserve their value across instances of the class. So the following code:

至于静态成员,它们在类的实例中保留它们的值。所以下面的代码:

struct A
{
static int a;
};
int main()
{
A first;
A second;
first.a = 3;
second.a = 4;
printf("%d", first.a);
}

will print 4, because first.a and second.a are essentially the same variable. As for the initialization, see this question.

将打印 4,因为 first.a 和 second.a 本质上是相同的变量。至于初始化,请看这个问题。

回答by Nik Bougalis

When you a declare a staticvariable at file scope, then that variable is only available in thatparticular file (technically, the *translation unit, but let's not complicate this too much). For example:

当您static在文件范围内声明一个变量时,该变量仅在特定文件中可用(从技术上讲,是 *translation 单元,但我们不要将其复杂化太多)。例如:

a.cpp

a.cpp

static int x = 7;

void printax()
{
    cout << "from a.cpp: x=" << x << endl;
}

b.cpp

b.cpp

static int x = 9;

void printbx()
{
    cout << "from b.cpp: x=" << x << endl;
}

main.cpp:

主.cpp:

int main(int, char **)
{
    printax(); // Will print 7
    printbx(); // Will print 9

    return 0;
}

For a localvariable, staticmeans that the variable will be zero-initialized andretain its value between calls:

对于局部变量,static意味着该变量将被零初始化在调用之间保留其值:

unsigned int powersoftwo()
{
    static unsigned lastpow;

    if(lastpow == 0)
        lastpow = 1;
    else
        lastpow *= 2;

    return lastpow;
}

int main(int, char **)
{
    for(int i = 0; i != 10; i++)
        cout << "2^" << i << " = " << powersoftwo() << endl;
}

For classvariables, it means that there is only a single instance of that variable that is shared among all members of that class. Depending on permissions, the variable can be accessed from outside the class using its fully qualified name.

对于变量,这意味着该变量只有一个实例在该类的所有成员之间共享。根据权限,可以使用其完全限定名称从类外部访问该变量。

class Test
{
private:
    static char *xxx;

public:
    static int yyy;

public:
    Test()
    {        
        cout << this << "The static class variable xxx is at address "
             << static_cast<void *>(xxx) << endl;
        cout << this << "The static class variable yyy is at address "
             << static_cast<void *>(&y) << endl;
    }
};

// Necessary for static class variables.
char *Test::xxx = "I'm Triple X!";
int Test::yyy = 0;

int main(int, char **)
{
    Test t1;
    Test t2;

    Test::yyy = 666;

    Test t3;
};

Marking a non-class function as staticmakes the function only accessible from that file and inaccessible from other files.

将非类函数标记为static只能从该文件访问该函数而无法从其他文件访问该函数。

a.cpp

a.cpp

static void printfilename()
{ // this is the printfilename from a.cpp - 
  // it can't be accessed from any other file
    cout << "this is a.cpp" << endl;
}

b.cpp

b.cpp

static void printfilename()
{ // this is the printfilename from b.cpp - 
  // it can't be accessed from any other file
    cout << "this is b.cpp" << endl;
}

For class member functions, marking them as staticmeans that the function doesn't need to be called on a particular instance of an object (i.e. it doesn't have a thispointer).

对于类成员函数,将它们标记为static意味着不需要在对象的特定实例上调用该函数(即它没有this指针)。

class Test
{
private:
    static int count;

public:
    static int GetTestCount()
    {
        return count;
    };

    Test()
    {
        cout << this << "Created an instance of Test" << endl;
        count++;
    }

    ~Test()
    {
        cout << this << "Destroyed an instance of Test" << endl;
        count--;
    }
};

int Test::count = 0;

int main(int, char **)
{
    Test *arr[10] = { NULL };

    for(int i = 0; i != 10; i++)
        arr[i] = new Test();

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    // now, delete them all except the first and last!
    for(int i = 1; i != 9; i++)
        delete arr[i];        

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    delete arr[0];

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    delete arr[9];

    cout << "There are " << Test::GetTestCount() << " instances of the Test class!" << endl;

    return 0;
}

回答by Jamin Grey

Static variables are shared between every instance of a class, instead of each class having their own variable.

静态变量在类的每个实例之间共享,而不是每个类都有自己的变量。

class MyClass
{
    public:
    int myVar; 
    static int myStaticVar;
};

//Static member variables must be initialized. Unless you're using C++11, or it's an integer type,
//they have to be defined and initialized outside of the class like this:
MyClass::myStaticVar = 0;

MyClass classA;
MyClass classB;

Each instance of 'MyClass' has their own 'myVar', but share the same 'myStaticVar'. In fact, you don't even need an instance of MyClass to access 'myStaticVar', and you can access it outside of the class like this:

“MyClass”的每个实例都有自己的“myVar”,但共享相同的“myStaticVar”。事实上,您甚至不需要 MyClass 的实例来访问“myStaticVar”,您可以像这样在类之外访问它:

MyClass::myStaticVar //Assuming it's publicly accessible.

When used inside a function as a local variable (and not as a class member-variable) the static keyword does something different. It allows you to create a persistent variable, without giving global scope.

当在函数内部用作局部变量(而不是类成员变量)时,static 关键字会做一些不同的事情。它允许您创建一个持久变量,而无需提供全局范围。

int myFunc()
{
   int myVar = 0; //Each time the code reaches here, a new variable called 'myVar' is initialized.
   myVar++;

   //Given the above code, this will *always* print '1'.
   std::cout << myVar << std::endl;

   //The first time the code reaches here, 'myStaticVar' is initialized. But ONLY the first time.
   static int myStaticVar = 0;

   //Each time the code reaches here, myStaticVar is incremented.
   myStaticVar++;

   //This will print a continuously incrementing number,
   //each time the function is called. '1', '2', '3', etc...
   std::cout << myStaticVar << std::endl;
}

It's a global variable in terms of persistence... but without being global in scope/accessibility.

就持久性而言,它是一个全局变量……但在范围/可访问性方面不是全局变量。

You can also have static member functions. Static functions are basically non-member functions, but inside the class name's namespace, and with private access to the class's members.

您还可以拥有静态成员函数。静态函数基本上是非成员函数,但在类名的命名空间内,并且可以对类的成员进行私有访问。

class MyClass
{
    public:
    int Func()
    {
        //...do something...
    }

    static int StaticFunc()
    {
        //...do something...
    }
};

int main()
{
   MyClass myClassA;
   myClassA.Func(); //Calls 'Func'.
   myClassA.StaticFunc(); //Calls 'StaticFunc'.

   MyClass::StaticFunc(); //Calls 'StaticFunc'.
   MyClass::Func(); //Error: You can't call a non-static member-function without a class instance!

   return 0;
}

When you call a member-function, there's a hidden parameter called 'this', that is a pointer to the instance of the class calling the function. Static member functions don'thave that hidden parameter... they are callable without a class instance, but also cannot access non-static member variables of a class, because they don't have a 'this' pointer to work with. They aren't being called on any specific class instance.

当您调用成员函数时,有一个名为“this”的隐藏参数,它是指向调用该函数的类的实例的指针。静态成员函数没有那个隐藏参数......它们可以在没有类实例的情况下调用,但也不能访问类的非静态成员变量,因为它们没有“this”指针可以使用。它们不会在任何特定的类实例上被调用。

回答by David Tr

I'm not a C programmer so I can't give you information on the uses of static in a C program properly, but when it comes to Object Oriented programming static basically declares a variable, or a function or a class to be the same throughout the life of the program. Take for example.

我不是 C 程序员,所以我无法正确地向您提供有关静态在 C 程序中使用的信息,但是当涉及到面向对象编程时,静态基本上声明了一个变量、函数或类是相同的在整个程序的生命周期中。举个例子。

class A
{
public:
    A();
    ~A();
    void somePublicMethod();
private:
    void somePrivateMethod();
};

When you instantiate this class in your Main you do something like this.

当你在 Main 中实例化这个类时,你会做这样的事情。

int main()
{
   A a1;
   //do something on a1
   A a2;
   //do something on a2
}

These two class instances are completely different from each other and operate independently from one another. But if you were to recreate the class A like this.

这两个类实例彼此完全不同,并且彼此独立运行。但是,如果您要像这样重新创建 A 类。

class A
{
public:
    A();
    ~A();
    void somePublicMethod();
    static int x;
private:
    void somePrivateMethod();
};

Lets go back to the main again.

让我们再次回到主要。

int main()
{
   A a1;
   a1.x = 1;
   //do something on a1
   A a2;
   a2.x++;
   //do something on a2
}

Then a1 and a2 would share the same copy of int x whereby any operations on x in a1 would directly influence the operations of x in a2. So if I was to do this

然后 a1 和 a2 将共享 int x 的相同副本,因此对 a1 中 x 的任何操作都会直接影响 a2 中 x 的操作。所以如果我要这样做

int main()
{
   A a1;
   a1.x = 1;
   //do something on a1
   cout << a1.x << endl; //this would be 1
   A a2;
   a2.x++;
   cout << a2.x << endl; //this would be 2 
   //do something on a2
}

Both instances of the class A share static variables and functions. Hope this answers your question. My limited knowledge of C allows me to say that defining a function or variable as static means it is only visible to the file that the function or variable is defined as static in. But this would be better answered by a C guy and not me. C++ allows both C and C++ ways of declaring your variables as static because its completely backwards compatible with C.

类 A 的两个实例共享静态变量和函数。希望这能回答你的问题。我对 C 的有限知识允许我说将函数或变量定义为静态意味着它只对函数或变量被定义为静态的文件可见。但这最好由 C 人员而不是我来回答。C++ 允许 C 和 C++ 两种方式将变量声明为静态变量,因为它与 C 完全向后兼容。

回答by justin

What does it mean with local variable? Is that a function local variable?

局部变量是什么意思?那是函数局部变量吗?

Yes - Non-global, such as a function local variable.

是 - 非全局变量,例如函数局部变量。

Because there's also that when you declare a function local as static that it is only initialized once, the first time it enters this function.

因为还有当你将一个函数 local 声明为 static 时,它只初始化一次,第一次进入这个函数。

Right.

对。

It also only talks about storage duration with regards to class members, what about it being non instance specific, that's also a property of static no? Or is that storage duration?

它也只讨论关于类成员的存储持续时间,它是非实例特定的,这也是静态否的属性吗?或者是那个存储期限?

class R { static int a; }; // << static lives for the duration of the program

that is to say, all instances of Rshare int R::a-- int R::ais never copied.

也就是说,在所有情况下,R份额int R::a-int R::a是永远不会被复制。

Now what about the case with static and file scope?

现在静态和文件范围的情况如何?

Effectively a global which has constructor/destructor where appropriate -- initialization is not deferred until access.

实际上是一个在适当情况下具有构造函数/析构函数的全局变量——初始化不会推迟到访问。

How does static relate to the linkage of a variable?

静态如何与变量的链接相关?

For a function local, it is external. Access: It's accessible to the function (unless of course, you return it).

对于本地函数,它是外部函数。访问:该函数可以访问它(当然,除非您返回它)。

For a class, it is external. Access: Standard access specifiers apply (public, protected, private).

对于一个类,它是外部的。访问:适用标准访问说明符(公共、受保护、私有)。

staticcan also specify internal linkage, depending on where it's declared (file/namespace).

static还可以指定内部链接,具体取决于它的声明位置(文件/命名空间)。

This whole static keyword is downright confusing

整个 static 关键字完全令人困惑

It has too many purposes in C++.

它在 C++ 中有太多用途。

can someone clarify the different uses for it English and also tell me when to initialize a static class member?

有人可以用英语阐明它的不同用途,并告诉我何时初始化静态类成员吗?

It's automatically initialized before mainif it's loaded and has a constructor. That might sound like a good thing, but initialization?order is largely beyond your control, so complex initialization becomes very difficult to maintain, and you want to minimize this -- if you must have a static, then function local scales much better across libraries and projects. As far as data with static storage duration, you should try to minimize this design, particularly if mutable (global variables). Initialization 'time' also varies for a number of reasons -- the loader and kernel have some tricks to minimize memory footprints and defer initialization, depending on the data in question.

main如果它被加载并有一个构造函数,它会在之前自动初始化。这听起来可能是件好事,但初始化?顺序在很大程度上超出了您的控制范围,因此复杂的初始化变得非常难以维护,您希望将其最小化——如果您必须有一个静态的,那么跨库函数局部规模要好得多和项目。至于具有静态存储持续时间的数据,您应该尽量减少这种设计,特别是在可变(全局变量)的情况下。初始化“时间”也因多种原因而变化——加载器和内核有一些技巧来最小化内存占用和延迟初始化,具体取决于相关数据。

回答by Nima Soroush

Static Object:We can define class members static using static keyword. When we declare a member of a class as static it means no matter how many objects of the class are created, there is only one copy of the static member.

静态对象:我们可以使用 static 关键字定义类成员静态。当我们将类的成员声明为静态时,这意味着无论创建了多少个类的对象,静态成员都只有一个副本。

A static member is shared by all objects of the class. All static data is initialized to zero when the first object is created, if no other initialization is present. We can't put it in the class definition but it can be initialized outside the class as done in the following example by redeclaring the static variable, using the scope resolution operator :: to identify which class it belongs to.

静态成员由类的所有对象共享。如果不存在其他初始化,则在创建第一个对象时,所有静态数据都将初始化为零。我们不能把它放在类定义中,但它可以在类之外初始化,如下例所示,通过重新声明静态变量,使用范围解析运算符 :: 来标识它属于哪个类。

Let us try the following example to understand the concept of static data members:

让我们尝试下面的例子来理解静态数据成员的概念:

#include <iostream>

using namespace std;

class Box
{
   public:
      static int objectCount;
      // Constructor definition
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // Increase every time object is created
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
   private:
      double length;     // Length of a box
      double breadth;    // Breadth of a box
      double height;     // Height of a box
};

// Initialize static member of class Box
int Box::objectCount = 0;

int main(void)
{
   Box Box1(3.3, 1.2, 1.5);    // Declare box1
   Box Box2(8.5, 6.0, 2.0);    // Declare box2

   // Print total number of objects.
   cout << "Total objects: " << Box::objectCount << endl;

   return 0;
}

When the above code is compiled and executed, it produces the following result:

上述代码编译执行后,会产生如下结果:

Constructor called.
Constructor called.
Total objects: 2

Static Function Members:By declaring a function member as static, you make it independent of any particular object of the class. A static member function can be called even if no objects of the class exist and the static functions are accessed using only the class name and the scope resolution operator ::.

静态函数成员:通过将函数成员声明为静态成员,可以使其独立于类的任何特定对象。即使不存在类的对象并且仅使用类名和作用域解析运算符 :: 访问静态函数,也可以调用静态成员函数。

A static member function can only access static data member, other static member functions and any other functions from outside the class.

静态成员函数只能访问静态数据成员、其他静态成员函数和类外部的任何其他函数。

Static member functions have a class scope and they do not have access to the this pointer of the class. You could use a static member function to determine whether some objects of the class have been created or not.

静态成员函数有一个类作用域,它们不能访问类的 this 指针。您可以使用静态成员函数来确定类的某些对象是否已创建。

Let us try the following example to understand the concept of static function members:

让我们尝试下面的例子来理解静态函数成员的概念:

#include <iostream>

using namespace std;

class Box
{
   public:
      static int objectCount;
      // Constructor definition
      Box(double l=2.0, double b=2.0, double h=2.0)
      {
         cout <<"Constructor called." << endl;
         length = l;
         breadth = b;
         height = h;
         // Increase every time object is created
         objectCount++;
      }
      double Volume()
      {
         return length * breadth * height;
      }
      static int getCount()
      {
         return objectCount;
      }
   private:
      double length;     // Length of a box
      double breadth;    // Breadth of a box
      double height;     // Height of a box
};

// Initialize static member of class Box
int Box::objectCount = 0;

int main(void)
{

   // Print total number of objects before creating object.
   cout << "Inital Stage Count: " << Box::getCount() << endl;

   Box Box1(3.3, 1.2, 1.5);    // Declare box1
   Box Box2(8.5, 6.0, 2.0);    // Declare box2

   // Print total number of objects after creating object.
   cout << "Final Stage Count: " << Box::getCount() << endl;

   return 0;
}

When the above code is compiled and executed, it produces the following result:

上述代码编译执行后,会产生如下结果:

Inital Stage Count: 0
Constructor called.
Constructor called.
Final Stage Count: 2