#include<iostream>
using namespace std;

int &fun()
{
    static int x = 10;
    return x;
}
int main()
{
    fun() = 30;
    cout << fun();
    return 0;
}



Output is 30 why not 10?
please explain me the concept of Lvalue..
Thank you in advanvce.

Recommended Answers

All 18 Replies

fun returns a reference to a static object, which you then set to 30. Subsequent calls to fun will return the same object, and you'll get the same value that you set.

Here is a slightly modified version of your code (in the function fun):

#include<iostream>
using namespace std;

int& fun()
{
   static int x = 10;
   cout << "In fun x = " << x << endl;
   return x;
}

int main()
{
   fun() = 30;
   cout << fun();

return 0;
}

The line static int x = 10; is only executed during the first call to the function, and after that the line is skipped on all subsequent calls to that function. An error would result if you tried to bring into existence the variable x if x already existed (which is does because it's declared static). So that line is skipped after the first call to the function. If you didn't use the keyword static then that line would be executed each time the function was called.

In Main, the line fun() = 30; is the first call to the function and so x is brought into existence and set to 10. Then right after that when x is returned (as a reference to x) then x is set to 30. Now since static int x = 10; is no longer executed anymore the function actually consists of just a return x statement (plus my cout statement : ). Try removing the static keyword from x and see what you get printed out on the screen.

An L value is something that can hold a value, like a memory location. An L value goes on the Left side of the assignment opperator and an R value goes on the right side.
Example: lvalue = 6;, or more literally, x = 6;. Obviously, x must be able to take on the value of 6, so x must be a memory location (as all variables are). If you have a function named foo, and all it does is print "Hello World" to the screen, then "foo = 6;" is not possible, because foo is not a memory location so foo is not a valid lvalue.

But when a function returns a reference, like fun does, then the name of that function represents the reference that is returned, and the reference is a valid lvalue. So fun() = 30 is valid, because that is the same thing as x& = 30 which is the same thing as x = 30.

commented: Good explanation! +14

The line static int x = 10; is only executed during the first call to the function,

The value of static variables is set at compile time just like all other global variables.

In Main, the line fun() = 30; is the first call to the function and so x is brought into existence and set to 10.

No. See my previous comment.

Thanks for the correction Ancient Dragon. But at least the effect is as if it happened as I stated, right?

Well, I have to correct the correction because what AD said is wrong. Local variables (defined in a function) with static storage duration (with static keyword) are created and initialized the first time control flows over that code (i.e., the first time the function is called). MandrewP was entirely correct. The C++ standard is 100% clear on this issue, and I don't know of any compiler that does not apply this correctly.

For example, this code is perfectly correct:

int get_first_value(int value) {
  static int x = value;
  return x;
};

int main() {
  std::cout << get_first_value(42) << std::endl;
  std::cout << get_first_value(69) << std::endl;
};

And it prints out 42 and 42, as expected. And, of course, the above code would be impossible if local static variables were "just like all other global variables".

Of course, if the type is just an integer (not a class with a non-trivial constructor) and the value it's initialized with is a compile-time constant, then that would allow the compiler to optimize this code by making it a statically-initialized static-duration variable, i.e., a normal global variable. In that sense, in this particular example, what AD said is probably true in practice, but it's an "as if" optimization case (i.e., it can be made into a global variable while looking "as if" it was a local static variable).

The only way to know one way or the other is to look at the assembly code that the compiler produces. Below is from Visual Studio 2012. Nowhere in there does it show the static variable being initialized when foo() is entered the first time, because the initialization is performed when the variable is declared -- see the line ?x@?1??foo@@YAAAHXZ@4HA DD 0aH ;foo'::2'::x. The 0aH is initializing the variable

This is only true for static variables of POD (Plain Old Data) types.

The program is compiled in Release mode to prevent generation of debug info.

; Listing generated by Microsoft (R) Optimizing Compiler Version 17.00.60610.1 

    TITLE   C:\dvlp\ConsoleApplication5\ConsoleApplication5\ConsoleApplication5.cpp
    .686P
    .XMM
    include listing.inc
    .model  flat

INCLUDELIB OLDNAMES

PUBLIC  ??_C@_0BA@NLKDPCHC@Hello?5World?5?$CFd?6?$AA@   ; `string'
EXTRN   __imp__printf:PROC
EXTRN   @__security_check_cookie@4:PROC
;   COMDAT ?x@?1??foo@@YAAAHXZ@4HA
_DATA   SEGMENT
?x@?1??foo@@YAAAHXZ@4HA DD 0aH              ; `foo'::`2'::x
_DATA   ENDS
;   COMDAT ??_C@_0BA@NLKDPCHC@Hello?5World?5?$CFd?6?$AA@
CONST   SEGMENT
??_C@_0BA@NLKDPCHC@Hello?5World?5?$CFd?6?$AA@ DB 'Hello World %d', 0aH, 00H ; `string'
CONST   ENDS
PUBLIC  _main
PUBLIC  ?foo@@YAAAHXZ                   ; foo
; Function compile flags: /Ogtp
; File c:\dvlp\consoleapplication5\consoleapplication5\consoleapplication5.cpp
;   COMDAT ?foo@@YAAAHXZ
_TEXT   SEGMENT
?foo@@YAAAHXZ PROC                  ; foo, COMDAT

; 8    :    static int x = 10;
; 9    :    printf("Hello World %d\n", x);

    push    DWORD PTR ?x@?1??foo@@YAAAHXZ@4HA
    push    OFFSET ??_C@_0BA@NLKDPCHC@Hello?5World?5?$CFd?6?$AA@
    call    DWORD PTR __imp__printf
    add esp, 8

; 10   :    return x;

    mov eax, OFFSET ?x@?1??foo@@YAAAHXZ@4HA

; 11   : }

    ret 0
?foo@@YAAAHXZ ENDP                  ; foo
_TEXT   ENDS
; Function compile flags: /Ogtp
; File c:\dvlp\consoleapplication5\consoleapplication5\consoleapplication5.cpp
;   COMDAT _main
_TEXT   SEGMENT
_main   PROC                        ; COMDAT

; 9    :    printf("Hello World %d\n", x);

    push    DWORD PTR ?x@?1??foo@@YAAAHXZ@4HA
    push    OFFSET ??_C@_0BA@NLKDPCHC@Hello?5World?5?$CFd?6?$AA@
    call    DWORD PTR __imp__printf
    add esp, 8

; 16   :    foo() = 30;

    mov DWORD PTR ?x@?1??foo@@YAAAHXZ@4HA, 30   ; 0000001eH

; 17   :    return 0;

    xor eax, eax

; 18   : }

    ret 0
_main   ENDP
_TEXT   ENDS
END

There is the source for the above assembly code

#include <stdio.h>

int& foo()
{
    static int x = 10;
    printf("Hello World %d\n", x);
    return x;
}


int main()
{
    foo() = 30;
    return 0;
}

And it prints out 42 and 42, as expected. And, of course, the above code would be impossible if local static variables were "just like all other global variables".

No -- that would be impossible if the static variable were on the stack just like any other non-static local variable. Static variables actually reside in global data segment, Visual Studio puts them in COMDAT data segment (lines 15-17 of the assembly code).

AD: I don't believe that Mike_200_17 is disagreeing with you about where static variables are kept, but rather about when and how they are initialized. He is saying that, unlike a globabl variable, which is initialized at the time the process running the program begins, static variables are initialized on the first pass through the function they are local to. The fact that they are global memory doesn't change the fact that the scope of the variable is local to the function, nor does it mean that initialization has to be done at the start of the process. These are the two distinguishing features of function-level static variables, really.

static variables are initialized on the first pass through the function they are local to. T

No they are not -- static POD variables are initialized just like all other global POD variables. I posted assembly code to prove it. It would be ridiculous and unnecessarily time consuming to put if statements inside functions to initialize static variables the first time the function is entered.

The fact that they are global memory doesn't change the fact that the scope of the variable is local to the function,

I said nothing about the scope of the variables. That is the ONLY difference between static local variables and global variables.

Ok, to settle this, let's just look at what the C++ standard says. Here is the relevant section (that I already quoted in another recent thread where the properties of those variables is a critical part of the design) about block-scope variables (i.e., local variables) with static storage duration. Section 6.7/4:

The zero-initialization (8.5) of all block-scope variables with static storage duration (3.7.1) or thread storage duration (3.7.2) is performed before any other initialization takes place. 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; such a variable is considered initialized upon the completion of its initialization. If the initialization exits by throwing an exception, the initialization is not complete, so it will be tried again the next time control enters the declaration. If control enters the declaration concurrently while the variable is being initialized, the concurrent execution shall wait for completion of the initialization. If control re-enters the declaration recursively while the variable is being initialized, the behavior is undefined.

The translation into plain English is that if the variable has a trivial constructor (i.e. a POD type), and it is zero-initialized or constant-initialized, then it is permitted to initialize it as if it was a global variable (i.e. static-duration namespace-scope variable). This is only because it makes no "observable behavior" difference one way or the other. In all other cases though (non-trivial constructor, or non-constant initialization), the variable is initialized the first time control passes over the declaration (first time the block is executed / called).

In short, you can safely consider that all such variables are initialized the first time control passes over them, because it is only when it makes no observable behavior difference to initialize it before (along with the global variables) that that is done. It always behaves as if the variable is initialized on the first pass.

I said nothing about the scope of the variables. That is the ONLY difference between static local variables and global variables.

Absolutely not. Notwithstanding the POD optimization that I just mentioned, static local variables are very different from global variables. First, if a variable never got constructed (i.e., control never reached it), then it will not be destroyed, see Section 6.7/5:

The destructor for a block-scope object with static or thread storage duration will be executed if and only if it was constructed.

Second, the standard requires that all static local variables be destroyed before any of the glboal variables, and they will be destroyed in the exact reverse order that they were initialized (when control first reached them). Again, this does not apply to POD types since they don't (really) have a destructor.

No -- that would be impossible if the static variable were on the stack just like any other non-static local variable. Static variables actually reside in global data segment

I never said anything about those variables being on the stack. Of course, they don't reside on the stack, that's impossible. Of course they have to be somewhere in a global data segment. What I am talking about is to point at which they are initialized (constructed) and the point at which they are destroyed. This is well-defined (and thread-safe, btw), and is very different from global variables.

If I was wrong and you were right, I could not begin to tell you how much code would be broken out there. This has been a required mechanism for a robust Singletons or any robust "construct-on-first-use" global variables, to combat the static initialization order fiasco. I have used this mechanism for time to time. And I have used static local variables for simpler purposes too.

The point is, static local variables are initialized the first time control passes over them, period. Everything good programmer knows this and has used this special feature before.

AD, sorry that you had to feel my wrath.

commented: For quoting the standard. :) +13

static POD variables are initialized just like all other global POD variables. I posted assembly code to prove it.

In the case you give, where the static variable is initialized to a fixed value, the compiler is indeed initializing the variable at the start of the process; however, given that this is a reasonable optimization which can be shown to have no effect on program behavior, it is possible that the compiler generated the code in this manner for the sake of efficiency rather than strict compliance. The assembly output for the code given by Mike_2000_17, where the static variable is being initialized to a value passed at run time, would be more relevant for this matter. A modified version of that code would make the behavior clearer:

#include <cstdio>

int get_first_value(int value) {
  static int x = value;
  return x;
};

int main() {
  int n;
  printf("Enter a value to test: ");
  scanf("%d", &n);
  printf("%d\n", get_first_value(n));
  printf("%d\n", get_first_value(69));
};

Here, the initializing value will not be known at compile time at all; it would not be possible to have an initialization at the start of the process. And indeed, the program run comes out as follows:

$ ./testd.exe
Enter a value to test: 23
23
23

While I do not have a copy of VS on the system I am on right now, I do have GCC, and the (unoptimized) assembly output for this program comes out as:

    .file   "testd.cpp"
.lcomm _ZGVZ15get_first_valueiE1x,8,8
    .text
    .globl  _Z15get_first_valuei
    .def    _Z15get_first_valuei;   .scl    2;  .type   32; .endef
    .seh_proc   _Z15get_first_valuei
_Z15get_first_valuei:
.LFB7:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $32, %rsp
    .seh_stackalloc 32
    .seh_endprologue
    movl    %ecx, 16(%rbp)
    leaq    _ZGVZ15get_first_valueiE1x(%rip), %rax
    movzbl  (%rax), %eax
    testb   %al, %al
    jne .L2
    leaq    _ZGVZ15get_first_valueiE1x(%rip), %rcx
    call    __cxa_guard_acquire
    testl   %eax, %eax
    setne   %al
    testb   %al, %al
    je  .L2
    movl    16(%rbp), %eax
    movl    %eax, _ZZ15get_first_valueiE1x(%rip)
    leaq    _ZGVZ15get_first_valueiE1x(%rip), %rcx
    call    __cxa_guard_release
.L2:
    movl    _ZZ15get_first_valueiE1x(%rip), %eax
    addq    $32, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .def    __main; .scl    2;  .type   32; .endef
    .section .rdata,"dr"
.LC0:
    .ascii "Enter a value to test: \0"
.LC1:
    .ascii "%d\0"
.LC2:
    .ascii "%d\12\0"
    .text
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
.LFB8:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $48, %rsp
    .seh_stackalloc 48
    .seh_endprologue
    call    __main
    leaq    .LC0(%rip), %rcx
.LEHB0:
    call    printf
    leaq    -4(%rbp), %rax
    movq    %rax, %rdx
    leaq    .LC1(%rip), %rcx
    call    scanf
    movl    -4(%rbp), %eax
    movl    %eax, %ecx
    call    _Z15get_first_valuei
    movl    %eax, %edx
    leaq    .LC2(%rip), %rcx
    call    printf
    movl    $69, %ecx
    call    _Z15get_first_valuei
    movl    %eax, %edx
    leaq    .LC2(%rip), %rcx
    call    printf
.LEHE0:
    movl    $0, %eax
    jmp .L8
.L7:
    movq    %rax, %rcx
.LEHB1:
    call    _Unwind_Resume
.LEHE1:
.L8:
    addq    $48, %rsp
    popq    %rbp
    ret
    .def    __gxx_personality_seh0; .scl    2;  .type   32; .endef
    .seh_handler    __gxx_personality_seh0, @unwind, @except
    .seh_handlerdata
.LLSDA8:
    .byte   0xff
    .byte   0xff
    .byte   0x1
    .uleb128 .LLSDACSE8-.LLSDACSB8
.LLSDACSB8:
    .uleb128 .LEHB0-.LFB8
    .uleb128 .LEHE0-.LEHB0
    .uleb128 .L7-.LFB8
    .uleb128 0
    .uleb128 .LEHB1-.LFB8
    .uleb128 .LEHE1-.LEHB1
    .uleb128 0
    .uleb128 0
.LLSDACSE8:
    .text
    .seh_endproc
.lcomm _ZZ15get_first_valueiE1x,4,4
    .ident  "GCC: (GNU) 4.8.1"
    .def    __cxa_guard_acquire;    .scl    2;  .type   32; .endef
    .def    __cxa_guard_release;    .scl    2;  .type   32; .endef
    .def    printf; .scl    2;  .type   32; .endef
    .def    scanf;  .scl    2;  .type   32; .endef
    .def    _Unwind_Resume; .scl    2;  .type   32; .endef

This compares to the GCC output for your code as such:

    .file   "foo.cpp"
    .section .rdata,"dr"
.LC0:
    .ascii "Hello World %d\12\0"
    .text
    .globl  _Z3foov
    .def    _Z3foov;    .scl    2;  .type   32; .endef
    .seh_proc   _Z3foov
_Z3foov:
.LFB7:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $32, %rsp
    .seh_stackalloc 32
    .seh_endprologue
    movl    _ZZ3foovE1x(%rip), %eax
    movl    %eax, %edx
    leaq    .LC0(%rip), %rcx
    call    printf
    leaq    _ZZ3foovE1x(%rip), %rax
    addq    $32, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .def    __main; .scl    2;  .type   32; .endef
    .globl  main
    .def    main;   .scl    2;  .type   32; .endef
    .seh_proc   main
main:
.LFB8:
    pushq   %rbp
    .seh_pushreg    %rbp
    movq    %rsp, %rbp
    .seh_setframe   %rbp, 0
    subq    $32, %rsp
    .seh_stackalloc 32
    .seh_endprologue
    call    __main
    call    _Z3foov
    movl    $30, (%rax)
    movl    $0, %eax
    addq    $32, %rsp
    popq    %rbp
    ret
    .seh_endproc
    .data
    .align 4
_ZZ3foovE1x:
    .long   10
    .ident  "GCC: (GNU) 4.8.1"
    .def    printf; .scl    2;  .type   32; .endef

You will see that in the former case, the value of x (Z15get_first_valueiE1x with name mangling, line 109) is defined using .lcomm, which sets aside a local common (e.g., static) memory space but does not initialize it, whereas in the latter, the x (_ZZ3foovE1x, lines 50-51) variable is defined using .long, which does initialze the value. Thus, we can conclude that the latter is simply optimizing away the runtime initialization, something the compiler could not do in the former case.

Thanks for posting that assembly code Schol-R-LEA, it is actually very interesting to look at the assembly code for the initialization section:

    leaq    _ZGVZ15get_first_valueiE1x(%rip), %rax
    movzbl  (%rax), %eax
    testb   %al, %al
    jne .L2
    leaq    _ZGVZ15get_first_valueiE1x(%rip), %rcx
    call    __cxa_guard_acquire
    testl   %eax, %eax
    setne   %al
    testb   %al, %al
    je  .L2
    movl    16(%rbp), %eax
    movl    %eax, _ZZ15get_first_valueiE1x(%rip)
    leaq    _ZGVZ15get_first_valueiE1x(%rip), %rcx
    call    __cxa_guard_release
.L2:
    movl    _ZZ15get_first_valueiE1x(%rip), %eax
    addq    $32, %rsp
    popq    %rbp
    ret

I know that this looks like gibberish to the average guy, but with only minimal knowledge of assembly, one can see that this is a double-checked locking initialization.

GCC created a guard, accessed through _ZGVZ15get_first_valueiE1x, to indicate whether the variable has been initialized already or not. Then, it created variable itself, accessed through _ZZ15get_first_valueiE1x. The code, is, in fact, derived from this canonical implementation (used by GCC and LLVM, and probably others, since this is the best way to implement a standard-compliant initialization of block-scope static variables):

if ( obj_guard.first_byte == 0 ) {
  if ( __cxa_guard_acquire(&obj_guard) ) {
    try {
      ... initialize the object ...;
    } 
    catch (...) {
      __cxa_guard_abort(&obj_guard);
      throw;
    }
    ... queue object destructor with __cxa_atexit() ...;
    __cxa_guard_release(&obj_guard);
  }
}

Which, in this case is:

static int x;
static /*unknown type*/ x_guard;

if ( x_guard.first_byte == 0 ) {
  if ( __cxa_guard_acquire(&x_guard) ) {
    try {
      x = value;
    } 
    catch (...) {
      __cxa_guard_abort(&x_guard);
      throw;
    }
    __cxa_atexit(/*destroy 'x' function*/);
    __cxa_guard_release(&x_guard);
  }
}

And because x is an integer, it does not have any destructor, and its initialization cannot throw an exception, therefore the code is optimized to this:

static int x;
static /*unknown type*/ x_guard;

if ( x_guard.first_byte == 0 ) {
  if ( __cxa_guard_acquire(&x_guard) ) {
    x = value;
    __cxa_guard_release(&x_guard);
  }
}

Which is exactly the code you can see in the assembly listing (plus the returning of the x value from the function).

And let me address a point I missed on the last post:

The only way to know one way or the other is to look at the assembly code that the compiler produces. Below is from Visual Studio 2012.

That's not true, especially not with a Microsoft compiler. The ultimate authority on what is the expected behavior of certain code is the ISO standard document, which is why I refer to it often. The assembly code produced by a particular compiler can be very deceiving, because (1) the compiler might not comply with the standard, (2) the compiler might have applied "as if" optimizations, and (3) any conclusions drawn pertain solely to this one particular compiler. The purpose of looking at assembly listings produced by a compiler is actually to investigate one of these aspects (e.g., "how compliant is my compiler?", or "how smart at optimization is my compiler?"), which is kind of what I did above when analysing the assembly that Schol-R-LEA posted. But to know what the expected behavior is, you have to refer to the standard.

And, the Microsoft compiler is notorious for being non-compliant with the standard and for being dismally bad at optimization (including producing slow code, but also breaking the "as if" rule). I don't know if 2012 has gotten much better, but, in any case, it will take time before Microsoft can re-build enough credibility with the C++ community to justify having anyone using the MSVC compiler as a "reference" for expected behavior.

Interesting, but this discuscussion is going way beyond the scope of the original question, which is how static variables are initialized with constant values.

I produced an assembly listing of the program that contains get_first_value() function, VS 2012 optimized out that function entirely and inlined the code. In this case, as expected, the static variable is not initialized with anything. The static variable is just simply set to the value of the parameter each time the function is called making it impossible to determine the initial value of x before the function is first called without checking the assembly code. Just like any other ordinary local variable the initial value of x is undefined.

Ok! We have on your right, Assember Wars! :-) AD and M2K, please just agree to disagree, ok?

As for static variable instantiation, I do believe that is a compiler implementation issue. IE, it may be like globals (at compile time), or it may be at run time (when the variable scope is first entered). Personally, I really don't give a darn since the effect (as far as I can tell) is the same...

So, shake hands, and go get a beer!

P.S. After a hard day of HTTP programming (another area where "standards" are not such), I am pouring myself a nice single-malt scotch whiskey!

Mike and I are actually saying the same thing, just in slightly different ways. The get_first_value() function he posted is not initializing x, it is just simply setting x to the value of the parameter. That isn't the same thing as initializing x. That function could have been written like below, where x is an unitialized variable until it is set to the parameter.

int get_first_value(int value) {
  static int x;
  x = value;
  return x;
};

Now had the function been written like below, the value of x would be 10 even before get_first_value() is called. There is no executable code line that sets the value of x to 10, the variable is set to 10 at the time memory is reserved for the variable.

    int get_first_value(int value) {
      static int x = 10;
      x = value;
      return x;
    };

That function could have been written like below, where x is an unitialized variable until it is set to the parameter.

Absolutely not! If you think that, you did not get the point, at all!

If I use the implementation you provided into this program:

#include <iostream>

int get_first_value(int value) {
  static int x;
  x = value;
  return x;
};

int main() {
  std::cout << get_first_value(42) << std::endl;
  std::cout << get_first_value(69) << std::endl;
};

then, the resulting output is:

$ ./test_static_local
42
69

If I use my original implementation:

#include <iostream>

int get_first_value(int value) {
  static int x = value;
  return x;
};

int main() {
  std::cout << get_first_value(42) << std::endl;
  std::cout << get_first_value(69) << std::endl;
};

then, the output is:

$ ./test_static_local
42
42

You can try it for yourself, you are skeptic about it.

Because the value of x is initialized the first time control flows over it, that is, with the value 42 (which is passed on the first call). So, on the second call, even though 69 is passed, the value of x remains the same, i.e., 42, because the variable is already initialized, and won't be initialized again.

The get_first_value() function he posted is not initializing x, it is just simply setting x to the value of the parameter. That isn't the same thing as initializing x.

By "initialized", I mean initialized, as defined in the standard, which means, it is constructed (i.e., its constructor is called). For primitive types like int, there is no default constructor, so if you declare an int variable without an initial value, it will be left uninitialized (not given a value, i.e., contains junk). However, there is a copy-constructor, so if you declare it with an initial value (e.g., = value;), then it will be value-initialized (constructed) with that value. That is initialization. I do not mean "initializing" to mean "the first time you give it a value".

And no, in my get_first_value() function, the x variable is initialized (constructed) with the value of the parameter, as seen in the assembly code posted.

Here is a more unambiguous example (with a non-trivial type):

#include <iostream>
#include <string>

struct Foo {
  std::string name;

  Foo(const std::string& aName) name(aName) {
    std::cout << "Foo constructor! " << name << std::endl;
  };

  ~Foo() {
    std::cout << "Foo destructor! " << name << std::endl;
  };
};

Foo f_global("global");

void bar() {
  static Foo f_static("static");
};

int main() {
  Foo f_local("local");
  std::cout << "Main Started!" << std::endl;
  bar();
  std::cout << "Intermezzo..." << std::endl;
  bar();
  std::cout << "Main about to end." << std::endl;
  return 0;
};

And the output is this:

Foo constructor! global
Foo constructor! local
Main Started!
Foo constructor! static
Intermezzo...
Main about to end.
Foo destructor! local
Foo destructor! static
Foo destructor! global

Proving that the local static object is not constructed as the global variable is. It is initialized / constructed the first time control flows over the declaration.

AD and M2K, please just agree to disagree, ok?

I am pretty stubborn about that, I know. I cannot agree to disagree about something that is a fact. This is not a matter of opinion. I have been trying to tell AD about what the C++ ISO standard document requires and what any reasonably standard-compliant compiler produces in this case. I am not expressing an opinion, I am stating a fact, and painfully trying to explain it.

I have already agree with AD to some extent, that is, that in the case of a POD type (like an int) that is initialized with a constant value (or zero-initialized), it will be made into a regular global variable (with lexical scope restricted to the function body). But I only agree to that because the C++ ISO standard specifically allows it and it falls under the "as if" optimization category. Again, I am all for agree with what is factually accurate, that's all I want.

As always, Mike is correct; I stand corrected. The idom "You can't teach an old dog new tricks" is wrong.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.