213

Can someone please explain how static variables in member functions work in C++.

Given the following class:

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

If I declare multiple instances of A, does calling foo() on one instance increment the static variable i on all instances? Or only the one it was called on?

I assumed that each instance would have its own copy of i, but stepping through some code I have seems to indicate otherwise.

Felix Glas
  • 15,065
  • 7
  • 53
  • 82
monofonik
  • 2,735
  • 3
  • 20
  • 17

4 Answers4

228

Since class A is a non-template class and A::foo() is a non-template function. There will be only one copy of static int i inside the program.

Any instance of A object will affect the same i and lifetime of i will remain through out the program. To add an example:

A o1, o2, o3;
o1.foo(); // i = 1
o2.foo(); // i = 2
o3.foo(); // i = 3
o1.foo(); // i = 4
iammilind
  • 68,093
  • 33
  • 169
  • 336
  • 6
    Thanks for the good example! Would there be a way to actually achieve something that makes the scope of `static int i` specific to the instance, so that e.g. `o1.foo(); // i = 1` and `$o2.foo(); // i = 1` ...? – Stingery Mar 13 '14 at 10:16
  • 17
    Although this may not be the style you are looking for, making i a private data member of class A would have the effect you are describing. If you are concerned about name conflicts, you could add a prefix such as `m_` to indicate the status of i. – Carl Morris Oct 13 '14 at 17:37
  • 3
    Please, mention what happens if the class and method are templatized. – ytobi Aug 07 '20 at 21:20
  • 8
    @ytobi, in such case for every instance of the templated method of a normal/template class, a separate static variable will be created. That variable will be applicable only to those types. e.g. `template void foo (T t) {...}`. Now for `foo` there will be a `static int i` (say `foo::i`) and separate for `foo` there will be a separate `static int i` (say `foo::i`) and so on. `i` will be incremented separately for `foo` than from the `foo`. Hope that clears the doubt. – iammilind Aug 08 '20 at 11:37
  • To clarify, you'd need to set `i = 0;` in the OP's code in order to get this result. – Andrew Oct 18 '20 at 06:19
  • @Andrew, with standard conforming compilers, static variables are value initialised to 0 by default. – iammilind Oct 19 '20 at 03:40
  • Why? . . . . . . – Andrew Oct 19 '20 at 17:32
  • @Andrew, That is because local static variables are zero initialized if it is possible to do so. For e.g., see here: https://accu.org/journals/overload/25/139/brand_2379/ – Hari Mar 29 '23 at 07:52
  • @Hari All you've just done is said "X because X". – Andrew Mar 29 '23 at 19:15
  • @Andrew, I suppose I misunderstood your earlier question. Zero initializing variables of static storage duration seems to make intuitive sense. Unfortunately, I don't yet know of an official document discussing the motivation behind this language aspect. If someone can share it here that will be very interesting to read. Anyway, as the ACCU article says, it is a good idea to clearly initialize the variables. – Hari Mar 29 '23 at 19:26
  • 1
    @Hari This seems to be a poorly-formed "feature" then, because it disallows the developer to use the BSS segment and forces them to use the Data segment: https://en.wikipedia.org/wiki/Data_segment – Andrew Mar 30 '23 at 23:14
  • 2
    @Andrew You have raised an important point. It has been realized by the language developers. The compiler places such zero initialized variables in the .bss segment. From https://en.cppreference.com/w/cpp/language/initialization: Variables to be zero-initialized are placed in the .bss segment of the program image, which occupies no space on disk and is zeroed out by the OS when loading the program. – Hari Mar 31 '23 at 04:31
168

The keyword static unfortunately has a few different unrelated meanings in C++

  1. When used for data members it means that the data is allocated in the class and not in instances.

  2. When used for data inside a function it means that the data is allocated statically, initialized the first time the block is entered and lasts until the program quits. Also the variable is visible only inside the function. This special feature of local statics is often used to implement lazy construction of singletons.

  3. When used at a compilation unit level (module) it means that the variable is like a global (i.e. allocated and initialized before main is run and destroyed after main exits) but that the variable will not be accessible or visible in other compilation units.

I added some emphasis on the part that is most important for each use. Use (3) is somewhat discouraged in favor of unnamed namespaces that also allows for un-exported class declarations.

In your code the static keyword is used with the meaning number 2 and has nothing to do with classes or instances... it's a variable of the function and there will be only one copy of it.

As correctly iammilind said however there could have been multiple instances of that variable if the function was a template function (because in that case indeed the function itself can be present in many different copies in the program). Even in that case of course classes and instances are irrelevant... see following example:

#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;
}
6502
  • 112,025
  • 15
  • 165
  • 265
  • Anyone got a reference for "somewhat discouraged in favor of unnamed namespaces"? – austinmarton Oct 16 '15 at 00:50
  • 6
    @austinmarton: The phrase "The use of static to indicate 'local to translation unit' is deprecated in C++. Use unnamed namespaces instead (8.2.5.1)" is present on The C++ Programming Language in my edition (10th print, September 1999) at page 819. – 6502 Oct 16 '15 at 06:22
  • @iammilind (& OP) `static` does indeed have a few different meanings; however, I fail to see how saying those meanings are "**unrelated**" is justified. It always means, "Have only one of these per , which transcends ." – Andrew Oct 18 '20 at 06:16
  • @Andrew: `static` at compilation unit level means the opposite (it means "local to compilation unit") – 6502 Oct 18 '20 at 07:34
  • @austinmarton rather old comment, but by chance i came across this yesterday: https://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1012. The commitee even considered to deprecate that use of static because unnamed namespaced. The linked report is about (among other things) keeping that use of static even though an unnamed namespace can achieve the same – 463035818_is_not_an_ai Jun 24 '22 at 08:54
11

Static variables inside functions

  • Static variable is created inside a function is stored on program’s static memory not on the stack.

  • Static variable initialization will be done on the first call of the function.

  • Static variable will retain the value in multiple function calls

  • Lifetime of the static variable is Program

enter image description here

Examples

#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;
}

Output :

Static Variable

Variable Value : 0
Variable Value : 1
Variable Value : 2
Variable Value : 3
Variable Value : 4

Auto Variable

Variable Value : 0
Variable Value : 0
Variable Value : 0
Variable Value : 0
Variable Value : 0

Saurabh Raoot
  • 1,303
  • 3
  • 26
  • 31
  • Would "address" be a better word choice instead of "value"? The value changes, it is not a _const_. – fde-capu Apr 30 '21 at 15:03
  • Yes. We can show it with address as well. – Saurabh Raoot May 04 '21 at 02:04
  • I mean, instead of "Static variable will retain the value in multiple function calls" -> "Static variable will retain the memory address in multiple function calls (even if its value changes)". – fde-capu May 04 '21 at 17:11
  • What will happen if the function is defined in-class and the class definition is included multiple times in and across libraries, will it still remain one in a program? – Eugene Sep 24 '21 at 10:54
-2

Simplified answer:

Static variables, regardless whether they are members of a (non-templated) class or a (non-templated) function, behave - technically - like a global label which scope is limited to the class or function.

AustinWBryan
  • 3,249
  • 3
  • 24
  • 42
0xbadf00d
  • 17,405
  • 15
  • 67
  • 107
  • 14
    No. Globals are initialized at program startup, function statics are initialized at first use. This is a **big** difference. – 6502 Jun 03 '11 at 11:35
  • I don't think this is what happens. However, this should be compiler specific anyway. – 0xbadf00d Jun 03 '11 at 11:44
  • 2
    Then you think wrong: 3.6.1 in the C++ standard dictates that construction of object of namespace scope with static storage duration happens at startup; 6.7 (4) dictates that in general "... such a variable is initialized the first time control passes through its declaration; such a variable is considered initialized upon the completion of its initialization". By the way this initialization-on-first-use is very handy to implement lazy singleton construction. – 6502 Jun 03 '11 at 13:02
  • 1
    3.7.4: "Constant initialization (3.6.2) of a block-scope entity with static storage duration, if applicable, is performed before its block is first entered. An implementation is permitted to perform early initialization of other block-scope variables with static or thread storage duration under the same conditions that an implementation is permitted to statically initialize a variable with static or thread storage duration in namespace scope (3.6.2). Otherwise such a variable is initialized the first time control passes through its declaration;" – 0xbadf00d Jun 03 '11 at 13:09
  • So, I don't think I'm wrong. I don't know wheter we are talking about the same thing or not. You're right in a case where constant initialization is not possible. Then "such a variable is initialized the first time control passes through its declaration;". – 0xbadf00d Jun 03 '11 at 13:10
  • I'm not sure if you really don't get it or if you just like to fight for some reason I don't understand. Of course if your program cannot tell if the initialization could have been done before then the implementation is free to do that before (but then again how can you tell it did it before?). If on the other side you're in the only interesting case to discuss, i.e. you can tell the difference because for example your static is an instance of a class and constructor has side effects then it MUST be done the first time the block is entered. – 6502 Jun 03 '11 at 17:50
  • I've never said anything other than that. I was just speaking of constant initialization. – 0xbadf00d Jun 04 '11 at 05:13
  • 1
    Curiously enough however: 1) for constant initialization it's irrelevant discussing if a local static can be initialized before entering the block the first time (the variable is only visible inside the block and constant initialization produces no side effects); 2) nothing in your post is said about constant initialization; 3) local statics are very useful for non-constant initialization like `MyClass& instance(){ static MyClass x("config.ini"); return x; }` - a valid portable implementation for single-thread use exactly because local statics are NOT simply like a global despite what you say. – 6502 Jun 04 '11 at 06:28