The Storage class in C++ defines the scope, life-time and where to store a variable in C++ program. These specifiers precede the type that they modify. There are four storage classes defined in C++ programming language
- auto
- static
- register
- extern
auto Storage Class
A variable which is declared inside a function or block is automatic variable by default. We can declare automatic variables using auto keyword, but it is rarely used because by default every local variable is automatic variable.
For Example :int count; auto int size;Both count and size are automatic variable. C++ Local Variable(auto) Example Program
#include <iostream> using namespace std; int main(){ // Automatic variable by default int a = 5; // Declaration of automatic variables using auto keyword auto int b = 10; cout << "Sum = " << a+b; return 0; }Output
Sum = 15
static Storage Class
A local static variable is visible only inside their own function but unlike local variables, they retain their values between function calls. We can declare static variable by adding static keyword before data type in variable declaration statement.
static int count;
- Variables declared static are initialized to zero(or for pointers, NULL) by default.
- Static keyword has different effect on local and global variables.
- For local static variables, compiler allocates a permanent storage in heap like global variable, so that they can retain their values between function calls. Unlike global variables, local static variables are visible only within their function of declaration.
- For global static variables, compiler creates a global variable which is only visible within the file of declaration.
- In C++, when static is used on a class data member, it causes only one copy of that member to be shared by all objects of its class.
C++ Static Variable Example Program
In the following program, we declared a local and a static variable inside getVal function. Output of this programs shows that static variable retains it's value between successive function call whereas local variable vanishes when control exits function block.
#include <iostream> using namespace std; int printVal(){ // Declaring a loval static variable static int sVariable = 0; // Declaring a local variable int lVariable = 0; // Incrementing both variables sVariable++; lVariable++; // Static variable will retail it's value between successive function calls cout << "StaticVariable = "<<sVariable<<" LocalVariable = "<<lVariable; cout << endl; } int main(){ printVal(); printVal(); printVal(); printVal(); return 0; }Output
StaticVariable = 1 LocalVariable = 1 StaticVariable = 2 LocalVariable = 1 StaticVariable = 3 LocalVariable = 1 StaticVariable = 4 LocalVariable = 1
Static Functions
When a function is declared as static, its visibility is limited to the file in which it is declared. This is known as internal linkage.
static void internalFunction() { // This function is only visible within the same file }
register Storage Class
Declaring a variable with register keyword is a hint to the compiler to store this variable in a register of the computer's CPU instead of storing it in memory. Storing any variable in CPU register, will reduce the time of performing any operation on register variable. We can declare register variables using register keyword.
For Example :register int count;
- Declaring a variable as register is a request to the compiler to store this variable in CPU register, compiler may or may not store this variable in CPU register(there is no guarantee).
- Register variable was deprecated in C++11.
- The scope of register variables are same as automatic variables, visible only within their function.
- Frequently accessed variables like loop counters are good candidates for register variable.
- We can only declare local variables and formal parameters of a function as register variables, global register variables are not allowed.
C++ Register Variable Example Program
#include <iostream> using namespace std; int main(){ // Declaration of a variables using register keyword register int counter; int sum=0; // Variable counter is used frequently within for loop for(counter = 1; counter <= 500; counter++){ sum+= counter; } cout << "Sum = " << sum; return 0; }Output
Sum = 125250
extern Storage Class
External variables in C++ are variables which can be used across multiple files. We you can declare an external variable by preceding a variable name with extern specifier. The extern specifier only tells the compiler about the name and data type of variable without allocating any storage for it. However, if you initialize that variable, then it also allocates storage for the extern variable. The extern modifier is most commonly used when there are two or more files sharing the same global variables or functions.
- Variables declared extern are initialized to zero by default.
- The scope of the extern variable is global.
- The value of the external variable exists till program termination.
Impact on Memory
- Automatic Variables : Local variables with automatic storage duration are typically stored on the stack. They are automatically deallocated when the scope in which they are declared exits.
void exampleFunction() { int localVar; // Stored on the stack }
- Static Variables : Static variables are often stored in the data segment of the program's memory. They persist throughout the program's execution.
void increment() { // Stored in the data segment static int counter = 0; ++counter; }
- Dynamic Variables : Variables created dynamically using new are stored in the heap. They must be explicitly deallocated using delete to avoid memory leaks.
// Stored in the heap int* dynamicVar = new int; // ... // Deallocation to prevent memory leaks delete dynamicVar;
Understanding where variables are stored helps in optimizing memory usage and avoiding issues like stack overflow or memory leaks.
Best Practices of Using Storage Classes in C++
- Minimize Global Variables : Limit the use of global variables as they can lead to potential issues, such as unintended modifications and difficulties in understanding code dependencies.
// Avoid int globalVar = 42; // Prefer int main() { // Local variable int localVar = 42; // ... return 0; }
- Use const and constexpr : For variables that should not be modified, use const to make the intention clear to both the compiler and other developers. Additionally, prefer constexpr for values known at compile time.
const int constantValue = 100; constexpr double pi = 3.14;
- Avoid Unnecessary Use of register : Modern compilers are adept at register allocation, and the use of register is often unnecessary. Trust the compiler's optimization capabilities.
// Avoid register int counter; // Prefer int counter;
- Initialize Variables at the Point of Declaration : Initialize variables when they are declared to prevent the use of uninitialized values.
// Initialize at the point of declaration int initializedVar = 42;
- Avoid Memory Leaks : When working with dynamic memory allocation, ensure proper deallocation using delete to avoid memory leaks.
int* dynamicVar = new int; // ... // Deallocate to prevent memory leaks delete dynamicVar;
Conclusion
Storage classes in C++ wield a profound influence on how variables are managed in terms of scope, lifetime, and memory allocation. By comprehending the nuances of each storage class and embracing best practices, you empower yourself to write efficient, readable, and maintainable code.
As you continue your coding journey, may the mysteries of storage classes unravel before you, guiding you to make informed decisions and craft software that stands the test of time.