#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.
saurav2007 0 Newbie Poster
deceptikon 1,790 Code Sniper Team Colleague Featured Poster
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.
MandrewP 60 Junior Poster in Training
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.
Edited by MandrewP
mike_2000_17 commented: Good explanation! +14
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster
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.
Edited by Ancient Dragon
MandrewP 60 Junior Poster in Training
Thanks for the correction Ancient Dragon. But at least the effect is as if it happened as I stated, right?
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster
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).
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster
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;
}
Edited by Ancient Dragon
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster
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).
Edited by Ancient Dragon
Schol-R-LEA 1,446 Commie Mutant Traitor Featured Poster
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.
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster
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.
Edited by Ancient Dragon
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster
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.
deceptikon commented: For quoting the standard. :) +13
Schol-R-LEA 1,446 Commie Mutant Traitor Featured Poster
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.
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster
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.
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster
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.
Edited by Ancient Dragon
rubberman 1,355 Nearly a Posting Virtuoso Featured Poster
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!
rubberman 1,355 Nearly a Posting Virtuoso Featured Poster
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!
Edited by rubberman
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster
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;
};
Edited by Ancient Dragon
mike_2000_17 2,669 21st Century Viking Team Colleague Featured Poster
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.
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster
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.