Static variables in member functions
Asked Answered
P

4

218

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.

Phobia answered 3/6, 2011 at 5:33 Comment(0)
P
230

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
Perlis answered 3/6, 2011 at 5:37 Comment(12)
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 ...?Beaton
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.Hulen
Please, mention what happens if the class and method are templatized.Clearsighted
@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<typename T> void foo (T t) {...}. Now for foo<int> there will be a static int i (say foo<int>::i) and separate for foo<string> there will be a separate static int i (say foo<string>::i) and so on. i will be incremented separately for foo<int> than from the foo<string>. Hope that clears the doubt.Perlis
To clarify, you'd need to set i = 0; in the OP's code in order to get this result.Softfinned
@Andrew, with standard conforming compilers, static variables are value initialised to 0 by default.Perlis
Why? . . . . . .Softfinned
@Andrew, That is because local static variables are zero initialized if it is possible to do so. For e.g., see here: accu.org/journals/overload/25/139/brand_2379Rivi
@Rivi All you've just done is said "X because X".Softfinned
@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.Rivi
@Rivi 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: en.wikipedia.org/wiki/Data_segmentSoftfinned
@Softfinned 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 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.Rivi
R
169

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;
}
Rutherfurd answered 3/6, 2011 at 6:24 Comment(5)
Anyone got a reference for "somewhat discouraged in favor of unnamed namespaces"?Krall
@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.Rutherfurd
@Perlis (& 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 <context>, which transcends <context>."Softfinned
@Andrew: static at compilation unit level means the opposite (it means "local to compilation unit")Rutherfurd
@Krall rather old comment, but by chance i came across this yesterday: 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 sameArmoured
M
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

Meseems answered 1/9, 2019 at 2:4 Comment(4)
Would "address" be a better word choice instead of "value"? The value changes, it is not a const.Palmate
Yes. We can show it with address as well.Meseems
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)".Palmate
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?Legionnaire
M
-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.

Macswan answered 3/6, 2011 at 8:14 Comment(8)
No. Globals are initialized at program startup, function statics are initialized at first use. This is a big difference.Rutherfurd
I don't think this is what happens. However, this should be compiler specific anyway.Macswan
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.Rutherfurd
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;"Macswan
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;".Macswan
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.Rutherfurd
I've never said anything other than that. I was just speaking of constant initialization.Macswan
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.Rutherfurd

© 2022 - 2024 — McMap. All rights reserved.