c++ scope and lifetime

Scope and lifetime are independent but related ideas. Scope is the section of the program where a variable is visible. The lifetime of a variable is the interval of time that the variable exists.



.. scope

Scope: WHERE a variable is visible ================================== - variables visible within the function (or block) where declared { int Y; // visible area in yellow }
- also can see variables declared in an enclosing block if not 'masked' by other declarations { int B; // B visible in blue & yellow { int Y; // Y visible in yellow ONLY // can see B here also } }
An identifier declared within a block is accessible: - Within the block it's declared in until the end of block - By any blocks that are nested within that block if the nested block does not have an identifier with the same name
NOTE: ==== blocks are associated often with if while for functionA { { { { } } } }
RULE: ===== which variable do i use when there may be multiple with the same name? ---------------------------------------------------------------------- look in local block FIRST if ( found ) use that variable else { while ( not found && more blocks to look into ) { look outside to next enclosing block if found { use that variable break out of loop } } } if ( not found ) error - unknown variable!
EXAMPLE: ======= a block is marked by { , } and scope is defined by blocks { |-> int y = 55; | int x = 99; <-------------| | { | | int x = 88; <-------| | | { | | | int x = 1;<---| | | | cout << x;<---| | | |-----> cout << y; | | } | | cout << x; //88 <---| | } | cout << x; //99 <--------| } cout << x; // ERROR! <-------------?
EXAMPLE: ======= #include <iostream> using namespace std; int func2( int ); // proto int main( ) { int x, y, z; x = 7; y = 99; cout << y; // 99 z = func2( y ); cout << z; // 49 cout << x; // 7 return 0; } int func2( int x ) // def { // x is actually a copy of the value 99 int y; // THIS y is different from y in main int count = 0; y = x - 50; cout << y; // 49 cout << x; // 99 cout << ++count; // 1 - ALWAYS return y; // return 49 }

.. code with x, xx, xxx

OUTPUT? 23 46 46 198 198 ======= // xx xx xx xx xx #include <iostream> using namespace std; // xxx get x, give x, call xx, xetc... void xx( int& x ); int x; // ?? int main( ) { int x = 23; int xx; // will NOT compile here because xx is name of a function cout << "x = " << x << endl; xx( x ); cout << "x = " << x << endl; if (x > 0) { int x = 99; xx(x); cout << "x = " << x << endl; } return x; } // bad idea to name function and variables same name but does compile here void xx( int& x ) { int xx = 2; x = xx * x; cout << "x = " << x << endl; return; }

.. lifetime

Lifetime: HOW LONG a variable remains valid =========================================== - life of variable is life of function UNLESS... a variable is static (or global)
Automatic variable ================== memory is allocated at block entry and deallocated at block exit (default variables) int x; Static variable =============== memory remains allocated as long as the program executes and so RETAINS its value static variables declared within a block are local to the block static int x; Global ====== Variables declared outside of ANY block are static and have global visibility - DON'T ! EXAMPLE: ======= #include <iostream> using namespace std; int func2 (int); // proto int main() { int x, y, z; y = 99; cout << y; //99 z = func2(5); cout << z; //10 cout << x; //99 return 0; } int func2(int x) // def { int y; // THIS y is different from y in main static int count = 0; y = x * 2; //10 cout << y; cout << x; //5 cout << ++count; //1,2,3,4, etc... return y; }

.. global changes scope and lifetime - but DON'T

Global constants are acceptable and global structs are acceptable as neither of them are able to be changed during program execution.
Global variables are defined OUTSIDE of main (outside of any block). Since they can be changed at any time by any function, they are a maintenance nightmare. They also can cause structural dependencies within code. They are NOT acceptable!
EXAMPLE: ======= #include <iostream> using namespace std; int func2 (int); // proto int g = 100; // global variable int main() { int x, y, z; y = 99; cout << y; //99 z = func2(5); cout << z; //10 cout << x; //99 cout << g; // 100 - global variable return 0; } int func2(int x) // def { int y; // THIS y is different from y in main static int count = 0; y = x * 2; //10 cout << y; cout << g; // 100 - global variable cout << x; //5 cout << ++count; //1,2,3,4, etc... return y; }
Global Variables ================ Global variables are dangerous and are considered BAD programming Pass all data and info between functions by parameter Using global variables has side effects Any function that uses global variables - Is not independent - Usually it cannot be used in more than one program When things go wrong - Difficult to find what went wrong and where - Problems caused by global variables in one area of a program might be misunderstood as problems caused in another area

.. namespaces

Namespaces When a header file, such as iostream, is included in a program - Global identifiers in header file become global identifiers in the program If a global identifier in a program has the same name as one of the global identifiers in the header file - The compiler will generate a syntax error C++ attempts to solve problem of overlapping global identifier names with the namespace mechanism
The syntax of the statement namespace is: namespace namespace_name { members } where a member is usually a variable, a named constant, or a function
Accessing a namespace Member The scope of a namespace member is local to the namespace Two ways a namespace member can be accessed outside the namespace 1: namespace_name::identifier 2: using namespace namespace_name;
// What's this code do?? #include <iostream> namespace joe { int n = 555; // number to convert } using namespace std; int main() { int n = 999; cout << n << ' ' << joe::n << endl; return 0; }
OUTPUT: 999 555