0

So im currently learning about C++ memory allocation and static variable. I understand that local variables are allocated to the stack and generally not a good practice to be static. But are there any situations where the use of a local static variable would not work at all?

user3281114
  • 187
  • 9
  • 1
    muti-threaded program – Bryan Chen Mar 19 '14 at 21:23
  • 1
    I think a better question might be if there are any situations where it is a good idea for it to work? – crush Mar 19 '14 at 21:23
  • @MooingDuck As opposed to using class state? Doesn't seem like the optimal means of implementing a recursive function. I guess if it's a free floating function. Of course, you could just pass the state to the function. – crush Mar 19 '14 at 21:27
  • @BryanChen: the problem of multithreading and synchronization is orthogonal to static lifetime (you can have problems even calling methods of a dynamically allocated or stack allocated instances, for example). – 6502 Mar 19 '14 at 21:30
  • 1
    @6502 my point is that static variables are shared (and hence not thread-safe without synchronization) compare to non-shared local variables – Bryan Chen Mar 19 '14 at 21:34
  • Bryan, 6502, actually static local variables are initialized the first time the function is called, before any of your synchronization code can even kick in. So the point is totally moot: static CANNOT safely be used with multi-threaded programs (or you have to know that you need to call the function once before starting any thread, or only if a single thread at a time can call the function. So in other words, it's just not safe.) – Alexis Wilke Mar 19 '14 at 22:08

5 Answers5

0

I think you are confusing between the two.

There is a difference between a local variable and a local static variable. The former's life is till the function exits (allocated on the stack) where as the later exists till your program exits (allocated in the Global/Static area of your program memory).

brokenfoot
  • 11,083
  • 10
  • 59
  • 80
  • Unsure about static local variables. So in a situation like recursion, a static local variable would not work correctly? – user3281114 Mar 19 '14 at 21:26
  • 1
    Recursion works by passing on the value of the variable as a parameter, the code remains the same. If a variable is defined as static in a recursive function then the code will not remain same if the behavior in your code is dependent on this variable. – brokenfoot Mar 19 '14 at 21:31
0

Local static variables will get initialized only the first time. I don't think there is anything wrong with using a local static variable if you have the need for it.

Say, you need a particular thing to happen only once even though the the method can get called multiple times.

void foo()
{
    static bool bFoo = false;
    if (!bFoo)
    {
        Foo2();
        // Do something only once.
        bFoo = false;
    }
}

foo();
foo();

Calling the method more than once will only call the Foo2() method the first time and not the second.

Abhishek
  • 359
  • 1
  • 8
  • 1
    NOTE: this function is not thread-safe. You should use [`std::call_once`](http://en.cppreference.com/w/cpp/thread/call_once) instead. – Bryan Chen Mar 19 '14 at 21:37
0

A local static variable is not allocated on the stack and its life is from when you enter the scope where it's defined to the end of the program.

Sometimes they're used for lazy-initialized objects or for caching results.

6502
  • 112,025
  • 15
  • 165
  • 265
0

The biggest issue that I had with static variables was to force the proper initialization order. When you have very big project with many compilation units it's always good to be aware of that problem.

More info here - Static variables initialisation order.

Community
  • 1
  • 1
olgierdh
  • 151
  • 5
0

Local variable are allocated on the stack, so they are new each time you enter the function. This could be called "reentrant-compatible" and hence these can be used for multi-thread and recursive functions without any worries.

Static variables, on the other hand, have ONE allocation. So if you call the same function multiple times, you will see a single version of that variable. This is not considered reentrant since modifying that value has side effects that may not be what you'd otherwise expect.

One side note about multi-thread processes and local static variables: the first time you enter a function that has a static variable, it gets initialized under your feet, before any instructions of your code is executed. This means you have no means at all to protect that code from getting executed by more than one thread.

All that said, you should generally ask yourself: why would I want to use a static variable? And not the other way around (i.e. why should I not use it). There are a very few cases when it is useful. In most other cases, it is useless and should be avoided to avoid potential problems.

One place where it is often used is a singleton instance retrieval function:

my_object *get_instance()
{
    static my_object *singleton(NULL);

    if(singleton == NULL)
    {
        singleton = new my_object;
    }

    return singleton;
}

This works, although frankly I stopped using it in my C++. I now put the singleton variable in a so called "static" variable as in:

namespace
{
    my_object *singleton = NULL;
}

my_object *get_instance()
{
    if(singleton == NULL)
    {
        singleton = new my_object;
    }

    return singleton;
}

The reason for doing that is that way the singleton variable is initialized at startup time, instead of the first time the function is called. Pushing it a little further, you can place the variable in your class as a static variable member. As far as I know that's not any different from having it in a name-less namespace.

IMPORTANT NOTE: If you create a (large) static const local array, know that the first time you call the function, it will build the array "by hand", in INTEL assembly, something like this:

   lea pointer, %ecx
   mov 12345678, %eax
   mov %eax, (%ecx)
   mov 12345678, %eax
   mov %eax, (%ecx)
   mov 12345678, %eax
   mov %eax, (%ecx)
   mov 12345678, %eax
   mov %eax, (%ecx)
   mov 12345678, %eax
   mov %eax, (%ecx)
   ...

It's going to be slow and possibly HUGE. It is a lot better to put your [static] const array in your no name namespace and use that pointer. Then all that code disappears and you get a pre-initialized array directly loaded from disk at start time. (Obviously, if you create a large const array in a non-static local variable, you will get the same sort of code and in that case you'd want it static so it gets initialized only once, but then you realize you can put it in your no name namespace, and can optimize even more!)

Note that some people mentioned recursive functions as being a place where you probably don't want a static variable. I will now give you a case where you could use it and avoid "wasting" stack space. However, do NOT use that if you intend to make your software multi-threaded because in that case it would not work (not without some extra work and as I said before, in a multi-thread environment you cannot control the initialization of your static local variables.)

int recursive(int value)
{
    static int depth(0);

    if(depth > 100)
    {
        std::cerr "too many recursive calls, dying!\n";
        exit(1);
    }

    ++depth;
    [...]
    if(special-case)
    {
        r = recursive(other_value);
        [...]
    }
    [...]
    --depth;
    return result;
}

In this case you use a static variable which allows you to work in a simple recursive function and know if it calls itself too many times and breaks (exits here) if the recursion happens too much.

What I mean by "simple recursive function" is a function which cannot be called more than once for the computation it needs to do. (i.e. if it creates an object that calls that function anew, the depth parameter won't work as expected since it was go back to zero automatically!)

In most cases, however, it is easier and a lot safer to pretty much always avoid static local variables.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156